poj3565_KM不交叉边匹配

题意:坐标中存在点集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做就行了

你可能感兴趣的:(poj)