POJ 2446 Chessboard (二分匹配)

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #define maxn 1050//表示x集合和y集合中顶点的最大个数
 5 int nx,ny;//x集合和y集合中顶点的个数
 6 int edge[maxn][maxn];//edge[i][j]为1表示ij可以匹配
 7 int cx[maxn],cy[maxn];//用来记录x集合中匹配的y元素是哪个
 8 int visited[maxn];//用来记录该顶点是否被访问过
 9 int path(int u)
10 {
11     int v;
12     for(v=0;v<=ny;v++)
13      {
14          if(edge[u][v]&&!visited[v])
15         {
16            visited[v]=1;
17             if(cy[v]==-1||path(cy[v]))//如果y集合中的v元素没有匹配或者是v已经匹配,但是从cy[v]中能够找到一条增广路
18             {
19                 cx[u]=v;//这是无向图中才要的
20                 cy[v]=u;
21                 return 1;
22             }
23         }
24     }
25     return 0;
26 }
27 int maxmatch()
28 {
29     int res=0,i;
30     for(i=0;i<maxn;i++)
31        cx[i]=cy[i]=-1;//初始值为-1表示两个集合中都没有匹配的元素!
32     for(i=0;i<=nx;i++)
33     {
34         if(cx[i]==-1)
35         {
36             memset(visited,0,sizeof(visited));
37             res+=path(i);
38         }
39     }
40     return res;
41  }
42 int main()
43 {
44     int i,j,x,y,ans,n,m,k,s;
45     while(scanf("%d%d%d",&n,&m,&k)!=EOF)
46     {
47         ny=nx=n*m;
48         memset(edge,0,sizeof(edge));
49         s=1;
50         for(i=1;i<=n;i++)
51             for(j=1;j<=m;j++)
52             {
53                 if(i>1)edge[s-m][s]=1;
54                 if(i<n)edge[s+m][s]=1;
55                 if(j>1)edge[s][s-1]=1;
56                 if(j<m)edge[s][s+1]=1;
57                 s++;
58             }
59         for(i=0;i<k;i++)
60             {
61                 scanf("%d%d",&y,&x);
62                 s=(x-1)*m+y;
63                 //printf("s=%d
",s);
64                 if(x>1)edge[s-m][s]=edge[s][s-m]=0;
65                 if(x<n)edge[s+m][s]=edge[s][s+m]=0;
66                 if(y>1)edge[s][s-1]=edge[s-1][s]=0;
67                 if(y<m)edge[s][s+1]=edge[s+1][s]=0;
68             }
69         /*for(i=1;i<=m*n;i++)
70             for(j=1;j<=m*n;j++)
71             {
72                 if(edge[i][j])
73                 printf("i=%d,j=%d,edge==%d
",i,j,edge[i][j]);
74             }*/
75         /*for(i=0;i<nx;i++)
76             for(j=0;j<ny;j++)
77            if(edge[i][j])printf("%d-->%d
",i,j);*/
78         ans=maxmatch();
79         if(ans==m*n-k)printf("YES
");
80         else printf("NO
");
81         //printf("%d
",ans);
82     }
83     return 0;
84 }
View Code

给图中每个格子编号,然后将之放入二分匹配中的两个集合里面,再将能连接即能覆盖的两个点连接起来。接下来就是模板的力量了。。。。赶脚这个构图法会是最猥琐的没有之一。

http://poj.org/problem?id=2446

原文地址:https://www.cnblogs.com/huzhenbo113/p/3687316.html