题目链接:
http://poj.org/problem?id=3565
题目大意:
在坐标系中有N只蚂蚁,N棵苹果树,给你蚂蚁和苹果树的坐标。让每只蚂蚁去一棵苹果树,
一棵苹果树对应一只蚂蚁。这样就有N条直线路线,问:怎样分配,才能使总路程和最小,且
N条线不相交。
思路:
用一个图来说明思路。
假设A、B为蚂蚁,C、D为苹果树。则存在两种匹配:第一种是AD、BC,第二种是AC、BD。
根据三角形不等式AD+BC < AC+BD,最后得到很重要的一个性质——满足总路程之和最小
的方案一定不相交。现在来构建二分图,一边为蚂蚁,另一边为苹果树,以距离为边权值,题
目就变为了求带权二分图最小权和的最佳匹配。反向来思考,将距离乘以-1取负值建图,那么
就变为了求带权二分图最大权和的最佳匹配。直接用KM算法来做。
KM::点击打开链接
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int qwq = 0x3f3f3f;
double w[110][110], x[110], y[110];
double xx, yy;
double usex[1000], usey[1000], cx[110], cy[110];
int n,line[110], kk[110];
bool finds(int u)
{
usex[u] = 1;
for (int i = 1; i <= n; i++)
{
if (!usey[i] && fabs(cx[u] + cy[i]-w[u][i]) <1e-5)
{
usey[i] = 1;
if (!line[i] || finds(line[i]))
{
line[i] = u;
return true;
}
}
}
return false;
}
void km()
{
memset(line, 0, sizeof(line));
for (int i = 1; i <= n; i++)
{
while (1) {
memset(usex, 0, sizeof(usex));
memset(usey, 0, sizeof(usey));
if (finds(i))break;
double d = qwq;
for (int j = 1; j <= n; j++)
{
if (usex[j])
{
for (int k = 1; k <= n; k++)
{
if (!usey[k])
{
d = min(d, cx[j] + cy[k] - w[j][k]);
}
}
}
}
for (int j = 1; j <= n; j++)
{
if (usex[j])
cx[j] -= d;
}
for (int j = 1; j <= n; j++)
{
if (usey[j])
cy[j] += d;
}
}
}
for (int i = 1; i <= n; i++)
{
kk[line[i]] = i;
}
for (int i = 1; i <= n; i++)
{
cout << kk[i] << endl;
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> x[i] >> y[i];
}
memset(w, 0, sizeof(w));
for (int i = 1; i <= n; i++)
{
cin >> xx >> yy;
for (int j = 1; j <= n; j++)
{
w[j][i] = -sqrt((x[j] - xx)*(x[j] - xx) + (y[j] - yy)*(y[j] - yy));
}
}
for (int i = 1; i <= n; i++)
{
double d = -qwq;
for (int j = 1; j <= n; j++)
{
d = max(d, w[i][j]);
}
cx[i] = d;
cy[i] = 0;
}
km();
return 0;
}