我的问题如下:
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,这似乎与我的问题相似,但不同的是,它只是试图找到一个匹配,但不是试图最小化某种距离。
有没有人知道类似的问题甚至解决方案?我错过了什么?问题实际上看起来并不那么困难,但我无法想出最佳解决方案。
答案 0 :(得分:5)
由于Edmonds(Blossom算法),有一个原始对偶算法,如果可能的话,你真的不想实现自己。 Vladimir Kolmogorov有implementation可能适合您的目的。
答案 1 :(得分:0)
尝试网络流量。最大流量是您要创建的对的数量。并计算它的最低成本。
答案 2 :(得分:0)
现在这不是保证,只是预感。
您可以找到最短的一对,将其匹配,然后将其从集合中删除。
然后递归直到没有对。
这显然不是最佳选择。但是我有一个预感,就是次优与绝对最优解的比率是可以限制的。希望使用一些子模量参数并将其绑定到全局最优值的(1-1 / e)分数之内,但我无法做到这一点。也许有人可以刺它。
答案 3 :(得分:0)
竞争编程3中有一个C ++记忆实现,如下所示(注意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;
}