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做就行了

posted @ 2012-07-21 08:47  pushing my way  阅读(550)  评论(0编辑  收藏  举报