UVALive 4043 Ants
题意:
给n个黑点和n个白点的坐标,然后连n条线段连接黑点和白点,使得所有线段不相交,求匹配方案。
解法:
白书上的例题,建图思路蛮好的。
二分图,黑点和白点在两个集合里。然后求最小匹配,这样的结果肯定保证线段不相交。为什么呢?
因为不存在三点共线,所以对于两条线段来说,如果他们相交了,我们可以交换一下匹配的点使得四个点构成两条不相交的线,这样结果肯定要变小,画个图就知道了。
p.s.貌似卡精度??被卡爆了。。。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cmath> 6 #define N 110 7 using namespace std; 8 typedef long long ll; 9 const double inf=1e40; 10 const double eps=1e-6; 11 double s[N][N],slack[N]; 12 double lx[N],ly[N]; 13 int mat[N],n; 14 bool vx[N],vy[N]; 15 bool dfs(int u){ 16 vx[u]=1; 17 for(int i=1;i<=n;i++){ 18 if(!vy[i]){ 19 double t=lx[u]+ly[i]-s[u][i]; 20 if(fabs(t)<eps){ 21 vy[i]=1; 22 if(mat[i]==-1||dfs(mat[i])){ 23 mat[i]=u; 24 return 1; 25 } 26 }else slack[i]=min(slack[i],t); 27 } 28 } 29 return 0; 30 } 31 void KM(){ 32 memset(mat,-1,sizeof(mat)); 33 memset(ly,0,sizeof(ly)); 34 for(int i=1;i<=n;i++){ 35 lx[i]=-inf; 36 for(int j=1;j<=n;j++) 37 lx[i]=max(lx[i],s[i][j]); 38 } 39 for(int i=1;i<=n;i++){ 40 for(int j=1;j<=n;j++)slack[j]=inf; 41 while(1){ 42 memset(vx,0,sizeof(vx)); 43 memset(vy,0,sizeof(vy)); 44 if(dfs(i))break; 45 double d=inf; 46 for(int j=1;j<=n;j++) 47 if(!vy[j])d=min(d,slack[j]); 48 for(int j=1;j<=n;j++) 49 if(vx[j])lx[j]-=d; 50 for(int j=1;j<=n;j++) 51 if(vy[j])ly[j]+=d; 52 } 53 } 54 for(int i=1;i<=n;i++) 55 printf("%d\n",mat[i]); 56 } 57 double bx[N],by[N],wx[N],wy[N]; 58 double dis(int i,int j){ 59 return sqrt((wx[i]-bx[j])*(wx[i]-bx[j])+(wy[i]-by[j])*(wy[i]-by[j])); 60 } 61 int main(){ 62 int flag=0; 63 while(cin>>n){ 64 for(int i=1;i<=n;i++)cin>>bx[i]>>by[i]; 65 for(int i=1;i<=n;i++)cin>>wx[i]>>wy[i]; 66 for(int i=1;i<=n;i++) 67 for(int j=1;j<=n;j++) 68 s[i][j]=-dis(i,j); 69 if(flag)printf("\n"); 70 KM(); 71 flag=1; 72 } 73 return 0; 74 }