题意:
给n只蚂蚁和n课苹果树的坐标,要让每只蚂蚁去一棵苹果树,路线不能交叉,求一种可行方案。
分析:
当某种匹配可行时蚂蚁所走的距离和是最小的,可以直接用KM算法求二分图最小权值匹配。还有一种做法是先假定一种匹配,如果其中有交叉就进行调整。
代码:
//poj 3565
//sep9
#include <iostream>
#include <cmath>
using namespace std;
const int maxN=128;
const double INF=999999999.0;
double w[maxN][maxN],lx[maxN],ly[maxN],slack[maxN];
int linky[maxN];
int visx[maxN],visy[maxN];
int nx,ny;
double antX[maxN],antY[maxN],appleX[maxN],appleY[maxN];
int ans[maxN];
bool find(int x)
{
visx[x]=true;
for(int y=0;y<ny;++y){
if(visy[y])
continue;
double t=lx[x]+ly[y]-w[x][y];
if(fabs(t)<1e-6){
visy[y]=true;
if(linky[y]==-1||find(linky[y])){
linky[y]=x;
return true;
}
}
else if(slack[y]>t)
slack[y]=t;
}
return false;
}
int KM()
{
int i,j;
memset(linky,-1,sizeof(linky));
for(i=0;i<nx;++i) ly[i]=0;
for(i=0;i<nx;++i)
for(j=0,lx[i]=-INF;j<ny;++j)
if(w[i][j]>lx[i])
lx[i]=w[i][j];
for(int x=0;x<nx;++x){
for(i=0;i<ny;++i)
slack[i]=INF;
while(1){
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(find(x))
break;
double d=INF;
for(i=0;i<ny;++i)
if(!visy[i]&&slack[i]<d)
d=slack[i];
if(d==INF)
return -1;
for(i=0;i<nx;++i)
if(visx[i])
lx[i]-=d;
for(i=0;i<ny;++i)
if(visy[i])
ly[i]+=d;
else
slack[i]-=d;
}
}
return 0;
}
double dis(double x1,double y1,double x2,double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
int n,i,j;
scanf("%d",&n);
for(i=0;i<n;++i)
scanf("%lf%lf",&antX[i],&antY[i]);
for(i=0;i<n;++i)
scanf("%lf%lf",&appleX[i],&appleY[i]);
for(i=0;i<n;++i)
for(j=0;j<n;++j)
w[i][j]=-dis(antX[i],antY[i],appleX[j],appleY[j]);
nx=ny=n;
KM();
for(i=0;i<n;++i)
ans[linky[i]]=i;
for(i=0;i<n;++i)
printf("%d\n",ans[i]+1);
return 0;
}