白书上二分图最佳匹配的例题,其中用到一个结论,就是两条线段相交会比不相交的情况长,然后转化为二分图最佳匹配即可。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> using namespace std; const int maxn=200; int n,x[2][maxn],y[2][maxn]; int link[maxn]; double dist[maxn][maxn],Lx[maxn],Ly[maxn]; bool S[maxn],T[maxn]; double Dis(int i,int j) { return sqrt((x[0][i]-x[1][j])*(x[0][i]-x[1][j])*1.0+1.0*(y[0][i]-y[1][j])*(y[0][i]-y[1][j])); } bool sq(double x,double y) { return fabs(x-y)<1e-9; } bool match(int i) { S[i]=true; for(int j=1;j<=n;j++) if(sq(Lx[i]+Ly[j],dist[i][j])&&!T[j]) { T[j]=true; if(!link[j]||match(link[j])) { link[j]=i; return true; } } return false; } void update() { double a=1<<30; for(int i=1;i<=n;i++) if(S[i]) for(int j=1;j<=n;j++) if(!T[j]) a=min(a,Lx[i]+Ly[j]-dist[i][j]); for(int i=1;i<=n;i++) { if(S[i]) Lx[i]-=a; if(T[i]) Ly[i]+=a; } } void KM() { for(int i=1;i<=n;i++) { link[i]=Lx[i]=Ly[i]=0; for(int j=1;j<=n;j++) Lx[i]=max(Lx[i],dist[i][j]); } for(int i=1;i<=n;i++) { for(;;) { memset(S,0,sizeof(S)); memset(T,0,sizeof(T)); if(match(i)) break; else update(); } } } int main() { bool first=false; while(scanf("%d",&n)!=EOF) { if(first) printf("\n"); first=true; for(int i=1;i<=n;i++) scanf("%d%d",&x[0][i],&y[0][i]); for(int i=1;i<=n;i++) scanf("%d%d",&x[1][i],&y[1][i]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dist[j][i]=-Dis(i,j); KM(); for(int i=1;i<=n;i++) printf("%d\n",link[i]); } return 0; }