题意:
给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; }
时间: 2024-11-06 16:49:19