二分图的拓展与应用:HDU 2819&&POJ 1486&&HDU 3488&&HDU1853

Swap HDU 2819

此题主要让我们发现匈牙利算法中记录匹配点编号数组的应用:

此数组记录的是左边的第几个与右边的第几个匹配

因为要求对角线匹配,那么进行两两移位就行了。。。

注意的是:你把横坐标的数放在左边,竖坐标的数放在右边的话,是移动C。

反过来就是移动R。

具体看代码:(注意红色字体部分

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<stdio.h>
 4 #include<string.h>
 5 using namespace std;
 6 int a[105][105],b[105],vis[105],a1[105],b1[105],n;
 7 int dfs(int x)
 8 {
 9     for(int i=1;i<=n;i++)
10         if(a[i][x]&&!vis[i])
11         {
12             vis[i]=1;
13             if(b[i]==-1||dfs(b[i]))
14             {
15                 b[i]=x;
16                 return 1;
17             }
18         }
19     return 0;
20 }
21 int main()
22 {
23     int i,j,ans,sum;
24     while(scanf("%d",&n)!=EOF)
25     {
26         for(i=1;i<=n;i++)
27             for(j=1;j<=n;j++)
28                 scanf("%d",&a[i][j]);//这里说明横坐标在左边(i),竖坐标在右边(j)
29         ans=0;
30         memset(b,-1,sizeof(b));
31         for(i=1;i<=n;i++)
32         {
33             memset(vis,0,sizeof(vis));
34             if(dfs(i))
35                 ans++;
36         }
37         if(ans<n)
38         {
39             printf("-1\n");
40             continue;
41         }
42         sum=0;
43         for(i=1;i<=n;i++)
44         {
45             for(j=i;j<=n;j++)
46                 if(b[j]==i)
47                     break;
48             if(i!=j)
49             {
50                 sum++;
51                 a1[sum]=i;
52                 b1[sum]=j;
53                 swap(b[i],b[j]);
54             }
55         }//移位的话,是一左边为基点,一个一个把左边的移好位
56         printf("%d\n",sum);
57         for(i=1;i<=sum;i++)
58             printf("R %d %d\n",a1[i],b1[i]);
59     }
60     return 0;
61 }

但是只要改一点点就行了!!!

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<stdio.h>
 4 #include<string.h>
 5 using namespace std;
 6 int a[105][105],b[105],vis[105],a1[105],b1[105],n;
 7 int dfs(int x)
 8 {
 9     for(int i=1;i<=n;i++)
10         if(a[x][i]&&!vis[i])
11         {
12             vis[i]=1;
13             if(b[i]==-1||dfs(b[i]))
14             {
15                 b[i]=x;
16                 return 1;
17             }
18         }
19     return 0;
20 }
21 int main()
22 {
23     int i,j,ans,sum;
24     while(scanf("%d",&n)!=EOF)
25     {
26         for(i=1;i<=n;i++)
27             for(j=1;j<=n;j++)
28                 scanf("%d",&a[i][j]);
29         ans=0;
30         memset(b,-1,sizeof(b));
31         for(i=1;i<=n;i++)
32         {
33             memset(vis,0,sizeof(vis));
34             if(dfs(i))
35                 ans++;
36         }
37         if(ans<n)
38         {
39             printf("-1\n");
40             continue;
41         }
42         sum=0;
43         for(i=1;i<=n;i++)
44         {
45             for(j=i;j<=n;j++)
46                 if(b[j]==i)
47                     break;
48             if(i!=j)
49             {
50                 sum++;
51                 a1[sum]=i;
52                 b1[sum]=j;
53                 swap(b[i],b[j]);
54             }
55         }
56         printf("%d\n",sum);
57         for(i=1;i<=sum;i++)
58             printf("C %d %d\n",a1[i],b1[i]);
59     }
60     return 0;
61 }

 但是我发现一个致命错误!!

上面的第一个代码:

没有进入dfs()的是横坐标,但是dfs()里面求的是以右括号的为定值,把左括号进行循环找出这个b[i]=x;

可以发现b[i]表示横坐标,那么下面移位的是b[i],则就是‘R’!!

Sorting Slides POJ 1486

这题主要考如何判断这个匹配是唯一的?(进行删边处理)

 

步骤:
1:求最大匹配,匹配边集合E
2:删除E中的一条边e,以e的一个端点找增广路,若不能找到增广路则e是必须边
3:恢复原图以及E,继续步骤2,直到E中的每条边都被删除过

 

分析:因为每个顶点只出现一次,那么每个顶点只关联两个顶点入度顶点和出度顶点,所以构造二分图,将一个点u拆成u,u'。那么对于这个二分图如果存在着完美匹配的话,那么原图中一定存在若干个环,环中包含每个顶点,对于权值之和最小,只需求最小权匹配即可。

这个题目不用求出匹配数是多少。。。

直接进行删边,有唯一的就输出。。。如果一个都没有就输出“none”。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<stdio.h>
 4 #include<string.h>
 5 using namespace std;
 6 int a1[105][105],vis[105],b[105],n;
 7 struct line
 8 {
 9     int x1;
10     int x2;
11     int y1;
12     int y2;
13 }a[105];
14 int dfs(int x)
15 {
16     for(int i=1;i<=n;i++)
17         if(a1[x][i]&&!vis[i])
18     {
19         vis[i]=1;
20         if(b[i]==-1||dfs(b[i]))
21         {
22             b[i]=x;
23             return 1;
24         }
25     }
26     return 0;
27 }
28 int main()
29 {
30     int d=0,i,j,x1,y1;
31     while(scanf("%d",&n)!=EOF)
32     {
33         if(n==0)
34             break;
35         if(d)
36             printf("\n");
37         for(i=1;i<=n;i++)
38             scanf("%d%d%d%d",&a[i].x1,&a[i].x2,&a[i].y1,&a[i].y2);
39         memset(a1,0,sizeof(a1));
40         for(i=1;i<=n;i++)
41         {
42             scanf("%d%d",&x1,&y1);
43             for(j=1;j<=n;j++)
44                 if(a[j].x1<x1&&a[j].x2>x1&&a[j].y1<y1&&a[j].y2>y1)
45                     a1[i][j]=1;
46         }
47         memset(b,-1,sizeof(b));
48         for(i=1;i<=n;i++)
49         {
50             memset(vis,0,sizeof(vis));
51             dfs(i);
52         }
53         printf("Heap %d\n",++d);
54         int flag=0;
55         for(i=1;i<=n;i++)//******************
56         {
57             int tmp=b[i];
58             b[i]=-1;
59             a1[tmp][i]=0;
60             memset(vis,0,sizeof(vis));//注意初始为零
61             if(!dfs(tmp))
62             {
63                 if(flag)
64                     printf(" ");
65                 printf("(%c,%d)",'A'+i-1,tmp);//注意的是把代表字母放到右边,那么判断直接输出就行了
66                 b[i]=tmp;
67                 flag=1;
68             }
69             a1[tmp][i]=1;
70         }//*********************删边处理
71         if(flag==0)
72             printf("none\n");
73         else
74             printf("\n");
75 
76     }
77     return 0;
78 }

 之后来个最小权匹配的例子:

Tour  HDU 3488

这里注意判断时,和输出时:(红色字体部分

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 #include<string.h>
 5 using namespace std;
 6 int inf=100000005;
 7 int lx[205],ly[205],a[205][205],vix[205],viy[205],slack[205],link[205],n;
 8 int dfs(int x)
 9 {
10     vix[x]=1;
11     for(int i=1;i<=n;i++)
12     {
13         if(viy[i])
14             continue;
15         if(a[x][i]!=-inf&&lx[x]+ly[i]==a[x][i])
16         {
17             viy[i]=1;
18             if(link[i]==-1||dfs(link[i]))
19             {
20                 link[i]=x;
21                 return 1;
22             }
23         }
24         else if(a[x][i]!=-inf)//这里知道一定有完美匹配了!如果没有就是个死循环
25         {
26             if(lx[x]+ly[i]-a[x][i]<slack[i])
27                 slack[i]=lx[x]+ly[i]-a[x][i];
28         }
29     }
30     return 0;
31 }
32 int main()
33 {
34     int t,m,a1,b1,c1,s,i,j;
35     scanf("%d",&t);
36     while(t--)
37     {
38         scanf("%d%d",&n,&m);
39         for(i=1;i<=n;i++)
40             for(j=1;j<=n;j++)
41             a[i][j]=-inf;
42         while(m--)
43         {
44             scanf("%d%d%d",&a1,&b1,&c1);
45             if(a[a1][b1]<-c1)
46                 a[a1][b1]=-c1;
47         }
48         memset(link,-1,sizeof(link));
49         memset(lx,-inf,sizeof(lx));
50         memset(ly,0,sizeof(ly));
51         for(i=1;i<=n;i++)
52             for(j=1;j<=n;j++)
53             if(a[i][j]>lx[i])
54                 lx[i]=a[i][j];
55         for(i=1;i<=n;i++)
56         {
57             for(j=1;j<=n;j++)
58                 slack[j]=inf;
59             while(1)
60             {
61                 memset(vix,0,sizeof(vix));
62                 memset(viy,0,sizeof(viy));
63                 if(dfs(i))
64                     break;
65                 int d=inf;
66                 for(j=1;j<=n;j++)
67                     if(!viy[j]&&d>slack[j])
68                         d=slack[j];
69                 for(j=1;j<=n;j++)
70                 {
71                     if(vix[j])
72                         lx[j]-=d;
73                     if(viy[j])
74                         ly[j]+=d;
75                     else
76                         slack[j]-=d;
77                 }
78             }
79         }
80         s=0;
81         for(i=1;i<=n;i++)
82             if(link[i]!=-1)
83                 s+=a[link[i]][i];
84         printf("%d\n",-s);
85     }
86     return 0;
87 }

 Cyclic Tour  HDU1853

 

这个题目和上面的差不多,但是他不一定有完美匹配!!! 

所以用上面的方法做不出来!!!

所以就要套用模板什么都不用改!在最后进行判断就行了!

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 #include<string.h>
 5 using namespace std;
 6 int inf=100000005;
 7 int lx[205],ly[205],a[205][205],vix[205],viy[205],slack[205],link[205],n;
 8 int dfs(int x)
 9 {
10     vix[x]=1;
11     for(int i=1;i<=n;i++)
12     {
13         if(viy[i])
14             continue;
15         if(lx[x]+ly[i]==a[x][i])
16         {
17             viy[i]=1;
18             if(link[i]==-1||dfs(link[i]))
19             {
20                 link[i]=x;
21                 return 1;
22             }
23         }
24         else
25         {
26             if(lx[x]+ly[i]-a[x][i]<slack[i])
27                 slack[i]=lx[x]+ly[i]-a[x][i];
28         }
29     }
30     return 0;
31 }
32 int main()
33 {
34     int m,a1,b1,c1,s,i,j;
35     while(scanf("%d%d",&n,&m)!=EOF)
36     {
37         for(i=1;i<=n;i++)
38             for(j=1;j<=n;j++)
39             a[i][j]=-inf;
40         while(m--)
41         {
42             scanf("%d%d%d",&a1,&b1,&c1);
43             if(a[a1][b1]<-c1)
44                 a[a1][b1]=-c1;
45         }
46         memset(link,-1,sizeof(link));
47         memset(lx,-inf,sizeof(lx));
48         memset(ly,0,sizeof(ly));
49         for(i=1;i<=n;i++)
50             for(j=1;j<=n;j++)
51             if(a[i][j]>lx[i])
52                 lx[i]=a[i][j];
53         for(i=1;i<=n;i++)
54         {
55             for(j=1;j<=n;j++)
56                 slack[j]=inf;
57             while(1)
58             {
59                 memset(vix,0,sizeof(vix));
60                 memset(viy,0,sizeof(viy));
61                 if(dfs(i))
62                     break;
63                 int d=inf;
64                 for(j=1;j<=n;j++)
65                     if(!viy[j]&&d>slack[j])
66                         d=slack[j];
67                 for(j=1;j<=n;j++)
68                 {
69                     if(vix[j])
70                         lx[j]-=d;
71                     if(viy[j])
72                         ly[j]+=d;
73                     else
74                         slack[j]-=d;
75                 }
76             }
77         }
78         s=0;
79         int s1=0;
80         for(i=1;i<=n;i++)//***********
81             {
82                 if(link[i]==-1||a[link[i]][i]==-inf)
83                 {
84                     s1=1;
85                     break;
86                 }
87                 s+=a[link[i]][i];
88             }//****************
89         if(s1==1)
90             printf("-1\n");
91         else
92             printf("%d\n",-s);
93     }
94     return 0;
95 }

 

posted on 2013-08-20 11:04  ~~碾压机  阅读(213)  评论(0编辑  收藏  举报