RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 622980
Accepted
Дмитрий Белоусов
Дмитрий Белоусов
Asked:2020-02-03 21:02:40 +0000 UTC2020-02-03 21:02:40 +0000 UTC 2020-02-03 21:02:40 +0000 UTC

应该用什么算法来解决这个问题?[关闭]

  • 772
关闭 这个问题是题外话。目前不接受回复。

寻求调试帮助的问题(“为什么这段代码不起作用? ”)应该包括所需的行为、具体问题或错误,以及在问题中正确重现它的最少代码。没有明确描述问题的问题对其他访问者来说是无用的。请参阅如何创建最小、独立且可重现的示例。

5 年前关闭。

改进问题

任务

我不知道要输出什么

олимпиада
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Qwertiy
    2020-02-03T21:22:30Z2020-02-03T21:22:30Z

    这是旅行推销员问题,通过枚举(带截止值)解决。

    考虑到点在一个平面上,可以优化其他东西,但是对于n<=12我觉得没有意义。

    • 3
  2. Best Answer
    KoVadim
    2020-02-03T22:32:16Z2020-02-03T22:32:16Z

    我喜欢@Qwertiy 的排列组合想法。我写的代码很流畅(代码很脏,用左脚写的,但一切都算对了)。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <limits>
    #include <cmath>
    
    using namespace std;
    
    struct point {
        double x;
        double y;
    };
    
    double dist(point x, point y) {
        return hypot(x.x-y.x, x.y-y.y);
    }
    
    double calc_len(const vector<point> &v, const vector<int> &d) {
        double l = 0;
        for (int i = 1; i < d.size(); i++) {
            l += dist(v[d[i-1]], v[d[i]]);
        }
        return l;
    }
    
    int main() {
        vector<point> v;
        int n;
        cin >> n;
        for (int i = 0; i < n; i++) {
            point p;
            cin >> p.x >> p.y;
            v.push_back(p);
        }
        vector<int> d;
        vector<int> min_r;
        double min_len = std::numeric_limits<double>::max();
        for (int i = 0; i< n; i++) { d.push_back(i); }
        do {
            double len = calc_len(v, d);
            cout << len << endl;
            if (len < min_len) {
                min_len = len;
                min_r = d;
            }
        } while ( std::next_permutation(begin(d)+1,end(d)-1) );
        cout << "len = " << min_len << endl;
        cout << "[";
        for (int x:min_r) { cout << " " << x+1; }
        cout << "]" << endl;
        return 0;
    }
    

    c++11中的距离计算已经可以这样写了

    double dist(point x, point y) {
        return hypot(x.x-y.x, x.y-y.y);
    }
    

    不是这样的

    double dist(point x, point y) {
        return sqrt((x.x-y.x) * (x.x-y.x) + (x.y-y.y) * (x.y-y.y));
    }
    

    PS 您需要在支持 c++11 的情况下进行编译。

    • 3
  3. Harry
    2020-02-04T02:22:55Z2020-02-04T02:22:55Z

    我看着@KoVadim 并在我的膝盖上画了草图 - 用剪裁分支......

    #include <vector>
    #include <iostream>
    #include <iomanip>
    
    using namespace std;
    
    struct pnt { double x, y; };
    
    double dist(pnt a, pnt b)    // Расстояние между точками
    {
        return hypot(a.x-b.x,a.y-b.y);
    }
    
    double path_len(const vector<pnt>& x, // Длина (части) выбранного пути
                    const vector<int>& p, size_t l)
    {
        double pl = 0.0;
        for(size_t i = 1; i <= l; ++i)
            pl += dist(x[p[i-1]],x[p[i]]);
        // Расстояние до последней точки, если еще не достали
        if (l != p.size()-1) pl += dist(x[p[l]],x[x.size()-1]);
        return pl;
    }
    
    struct Func
    {
        double min;               // Текущее минимальное расстояние
        const vector<pnt> * r;    // Массив точек
        vector<int>         save; // Сохраненная перестановка
    
        Func(const vector<pnt>& x):r(&x)
        {
            min = 0.0;
            for(size_t i = 1; i < x.size(); ++i)
                min += dist(x[i-1],x[i]);
        }
    
        // Проверка ветви
        bool operator()(const vector<int>& x, size_t l)
        {
            // Режем все, где неверное начало или конец
            if (x[0] != 0) return false;
            if (l != x.size()-1 && x[l] == x.size() - 1) return false;
            // Текущая длина
            double cur = path_len(*r,x,l);
            // Если больше минимальной - режем ветвь
            if (cur > min + min*DBL_EPSILON) return false;
            // Сохранение нового пути
            if (l == x.size()-1)
            {
                if (abs(min-cur) < 10.0*min*DBL_EPSILON)
                {
                    if (save > x) save = x;
                }
                else
                {
                    min = cur;
                    save = x;
                }
            }
            return true;
        }
    };
    
    // Ветвление и обрезка
    template<typename Func>
    bool branches(size_t N, Func& f, vector<int>*v_ = nullptr, size_t level = 0)
    {
        // Вспомогательный вектор
        vector<int> * vv = (level == 0) ? new vector<int> : v_;
        if (level == 0) for(size_t i = 0; i < N; ++i) vv->push_back(i);
        vector<int>& v = *vv;
    
        for(size_t i = level; i < N; ++i)
        {
            // Очередная перестановка
            std::swap(v[level],v[i]);
            if (f(v,level) && level < N-1) branches(N,f,vv,level+1);
            std::swap(v[i],v[level]);
    
        }
        if (level == 0) delete vv;
        return true;
    }
    
    
    int main(int argc, const char * argv[])
    {
        int N;
        cin >> N;
        vector<pnt> x;
        for(int i = 0; i < N; ++i)
        {
            cout <<"Point " << (i+1) << ": ";
            double xx, yy;
            cin >> xx >> yy;
            x.push_back(pnt{xx,yy});
        }
        Func f(x);
        branches(N,f);
        cout << f.min << endl;
        for(auto i: f.save) cout << (i+1) << "  ";
        cout << endl;
    
    }
    

    在 13 点的输入数据上,它在半秒内工作,@KoVadim 的迭代 - 37 秒;获得 12 分 - 分别为 0.17 秒和 3.1 秒......

    更新
    实验数据 -

    13
    0 0 1 0 2 0 3 0 0 1 1 1 2 1 3 1 0 2 1 2 2 2 3 2 0 3 1 3 2 3 3 3
    

    (我刚工作了16个点,嗯,为了不重写数据文件,我只改了第一个数)

    编译 - VC++ 2015,键cl /O2 /Ot /EHsc /FC /W4 /nologo /MT。我讨厌忍受 IDE :) 在没有特殊需要的情况下使用......
    我的变体hypot- 700±15ms。通过平方根的计算——他妈的,请原谅我的法语:大约 85±15 毫秒。他们在里面放了什么?可能是某种绕过可能溢出的可怕系统......

    来自@KoVadim 的程序在相同的编译条件下使用相同的数据 - 好吧,懒得运行十几次了,抱歉 - 给了 38 秒。答案不同,但最小距离相同。校正后hypot- 2.7 秒。

    人,不要用hypot!:) 顺便说一句,如果你只是预先计算距离表并从中取数据,你可以再次提高5的速度。

    以下是以 ms 为单位的近似(一次或两次运行)结果:

    Точек         KoVadim        Harry    Harry (hypot)  Harry (предвычисление
                                                          таблицы расстояний)
      12             230          30          180           12
      13            2700          75          700           24
      14           34700         380         3880           97
      15          484000        1950        23000          414
      16                        9400                      1880
    

    更新2

    同样用于比较 - 详尽搜索hypot13 个点计算 479001600 次,我的 - 8302951 ...

    更新3

    请参阅此处的最后一个选项 -如何正确并行化程序?

    • 3

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5