题意:坐标中存在点集X,Y(个数相同),每个点都有坐标标识,求边互不相交的完美匹配。
分析:这个题让我们联想到KM最小权值匹配,但是又不完全像,如果我们能证明最小权值和的匹配一定不相交的话,这个题就可以转化为kM最小权值匹配。
证明:假设A,B属于X点集,C,D属于Y点集,最小权值匹配AC和BD相交于E点,由三角形两边之和大于第三边,可得:AD+BC<AC+BD,这样就与最小权值匹配相矛盾。因此最小权值匹配中不能存在相交的边。得证。
证明比较容易,但是写代码的过程中,确遇到了很大的阻碍!!!
1.由于边是double型的,这样在比较两个double型的边是否相等时,应该a-b<=eps ,eps=1e-6;
2.至今不知道这是什么问题,我在find()函数中更新d值,就tle,而把更新的情况放在主函数中就A了,好纠结啊。
TLE的代码:
View Code
1 bool find(int i) 2 { 3 luse[i]=true; 4 int j; 5 for(j=1;j<=v;j++) 6 { 7 if(ruse[j]) continue; 8 if(array[i][j]==0) continue; 9 double t=array[i][j]-lapple[i]-rant[j]; 10 if(t<=eps) 11 { 12 ruse[j]=true; 13 if(res[j]==0 || find(res[j])) 14 { 15 res[j]=i; 16 return true; 17 } 18 } 19 // else if(t<d) 20 // d=t; 21 } 22 return false; 23 }
AC的代码:
View Code
1 #include <iostream> 2 #include <stdio.h> 3 #include <memory.h> 4 #include <math.h> 5 using namespace std; 6 7 const double inf=(1<<30); //好用 8 const int maxnum=101; 9 const double eps=1e-6; //double 型比较相等时,与这个比较 10 double array[maxnum][maxnum]; 11 12 typedef struct 13 { 14 double x,y; 15 }pp; 16 pp ant[maxnum],apple[maxnum]; 17 int res[maxnum]; 18 bool luse[maxnum]; 19 bool ruse[maxnum]; 20 double lapple[maxnum]; 21 double rant[maxnum]; 22 int v; 23 double d; 24 25 26 bool find(int i) 27 { 28 luse[i]=true; 29 int j; 30 for(j=1;j<=v;j++) 31 { 32 if(ruse[j]) continue; 33 if(array[i][j]==0) continue; 34 double t=array[i][j]-lapple[i]-rant[j]; 35 if(t<=eps) 36 { 37 ruse[j]=true; 38 if(res[j]==0 || find(res[j])) 39 { 40 res[j]=i; 41 return true; 42 } 43 } 44 // else if(t<d) 45 // d=t; 46 } 47 return false; 48 } 49 50 int main() 51 { 52 scanf("%d",&v); 53 int i,j,k; 54 for(i=1;i<=v;i++) 55 scanf("%lf%lf",&ant[i].x,&ant[i].y); 56 for(i=1;i<=v;i++) 57 scanf("%lf%lf",&apple[i].x,&apple[i].y); 58 59 memset(array,0,sizeof(array)); 60 memset(res,0,sizeof(res)); 61 for(i=1;i<=v;i++) 62 for(j=1;j<=v;j++) 63 array[i][j]=sqrt((apple[i].x-ant[j].x)*(apple[i].x-ant[j].x)+(apple[i].y-ant[j].y)*(apple[i].y-ant[j].y)); 64 65 for(i=1;i<=v;i++) 66 { 67 lapple[i]=inf; 68 rant[i]=0; 69 } 70 71 for(i=1;i<=v;i++) 72 for(j=1;j<=v;j++) 73 if(lapple[i]>array[i][j]) 74 lapple[i]=array[i][j]; 75 76 for(i=1;i<=v;i++) 77 { 78 while(1) 79 { 80 memset(luse,false,sizeof(luse)); 81 memset(ruse,false,sizeof(ruse)); 82 d=inf; 83 if(find(i)) 84 break; 85 86 for(j=1;j<=v;j++) 87 if(luse[j]) 88 for(k=1;k<=v;k++) 89 { 90 if(!ruse[k] && (array[j][k]-lapple[j]-rant[k]<d) ) 91 d=array[j][k]-lapple[j]-rant[k]; 92 } 93 94 for(j=1;j<=v;j++) 95 { 96 if(luse[j]) lapple[j]+=d; 97 if(ruse[j]) rant[j]-=d; 98 } 99 } 100 } 101 102 for(i=1;i<=v;i++) 103 printf("%d\n",res[i]); 104 return 0; 105 }
谁来告诉我有区别吗?
对了,这个题一开始我想以边的平方做,觉得这样可以避免double类型,结果WA了,就规规矩矩的用double做就行了