【问题标题】:Minimizing the distance of pairing points最小化配对点的距离
【发布时间】:2015-04-23 21:41:42
【问题描述】:

我的问题如下:

Given a number of 2n points, I can calculate the distance between all points 
and get a symmetrical matrix.

Can you create n pairs of points, so that the sum of the distance of all pairs is 
minimal?

EDIT: Every point has to be in one of the pairs. Which means that
every point is only allowed to be in one pair.

我曾经天真地尝试过使用匈牙利算法,希望它能给我一个作业,让作业是对称的。但这显然不起作用,因为我没有二分图。

经过一番搜索,我找到了Stable roommates problem,这似乎和我的问题类似,但不同的是,它只是试图找到匹配,而不是试图最小化某种距离。

有没有人知道类似的问题甚至解决方案?我错过了什么?这个问题实际上看起来并不难,但我就是想不出一个最佳的解决方案。

【问题讨论】:

  • 所以如果我理解正确的话,你有一个包含每个点之间距离的对称矩阵?为什么不将该矩阵转换为按距离 [start_point,end_point,distance] 排序的集合并选择前 n 对?
  • 每个点只允许一对。如果我只按距离排序,这不能保证。我应该将此添加到问题描述中。
  • 嗯,这确实使它变得更加困难。但是,您确定匈牙利算法不起作用吗?与其将其视为完整的无向图,不如将每个点拆分为两个点(源和目标),并将其视为完整的二分有向图。

标签: algorithm matrix hungarian-algorithm


【解决方案1】:

由于 Edmonds(Blossom 算法),有一个原始对偶算法,如果可能的话,你真的不想自己实现它。 Vladimir Kolmogorov 有一个implementation,可能适合您的目的。

【讨论】:

    【解决方案2】:

    尝试网络流。最大流量是您要创建的对数。并计算它的最低成本。

    【讨论】:

      【解决方案3】:

      现在这不是保证,而只是一种预感。

      你可以找到最短的对,匹配它们,然后将其从集合中移除。

      并递归,直到你没有剩下的对。

      这显然是次优的。但我有一种预感,这与绝对最优解的次优程度之比是有限的。希望是使用一些子模块化参数并将其绑定到全局最优的 (1 - 1 / e) 部分,但我无法做到。也许有人可以尝试一下。

      【讨论】:

        【解决方案4】:

        Competitive Programming 3 中有一个 C++ memoization 实现如下(注意 N 的最大值为 8):

        #include <algorithm>
        #include <cmath>
        #include <cstdio>
        #include <cstring>
        
        using namespace std;
        
        int N, target;
        double dist[20][20], memo[1<<16];
        
        double matching(int bitmask)
        {
            if (memo[bitmask] > -0.5)    // Already computed? Then return the result if yes
                return memo[bitmask];
            if (bitmask == target)       // If all students are already matched then cost is zero
                return memo[bitmask] = 0;
        
            double ans = 2000000000.0;        // Infinity could also work
            int p1, p2;
        
            for (p1 = 0; p1 < 2*N; ++p1)      // Find first non-matched point
                if (!(bitmask & (1 << p1)))
                    break;
            for (p2 = p1 + 1; p2 < 2*N; ++p2) // and pair it with another non-matched point
                if (!(bitmask & (1 << p2)))
                    ans = min(ans, dist[p1][p2]+matching(bitmask| (1 << p1) | (1 << p2)));
        
            return memo[bitmask] = ans;
        
        }
        

        然后是main方法(驱动代码)

        int main()
        {
            int i,j, caseNo = 1, x[20], y[20];
        
            while(scanf("%d", &N), N){
                 for (i = 0; i < 2 * N; ++i)
                     scanf("%d %d", &x[i], &y[i]);
                 for (i = 0; i < 2*N - 1; ++i)
                     for (j = i + 1; j < 2*N; ++j)
                          dist[i][j] = dist[j][i] = hypot(x[i]-x[j], y[i]-y[j]);
        
                 // use DP to solve min weighted perfect matching on small general graph
                 for (i = 0; i < (1 << 16); ++i) memo[i] = -1;
                 target = (1 << (2 * N)) - 1;
                 printf("Case %d: %.2lf", caseNo++, matching(0));
        
            }
            return 0;
        
        }
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-11-07
          • 1970-01-01
          • 2019-02-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-23
          • 2016-12-25
          相关资源
          最近更新 更多