poj 2226 二分匹配

  1 /*
  2 题意:给出一个r*c大小的草地,其中*表示泥地,.表示草地,给出若干宽1,长任意的木板,要求用这些木板垂直或水平
  3 覆盖泥地,但是不能覆盖了草地,木板可以相互重叠,问最少要多少块木板
  4 
  5 题解:最小点覆盖 == 最大匹配
  6 首先所有的泥地只用横向的木板覆盖,为每个板编号1~n1,然后只用纵向的木板覆盖,为每个板编号1~n2,然后纵横相交
  7 的点则加上一条边,从而建立起了二部图,其中的每条边都代表着需要覆盖的点,最后只需求出以最少的点覆盖所有的边
  8 即可,即求最小颠覆盖。
  9 */
 10 #include <cstdio>
 11 #include <cstring>
 12 
 13 #define clr(a,b) (memset(a,b,sizeof(a)))
 14 
 15 const int MAXV = 5005;
 16 const int MAXE = 10005;
 17 
 18 struct edge
 19 {
 20     int v,next;
 21 }E[MAXE];
 22 
 23 int EN;
 24 int mat[MAXV],head[MAXV];
 25 bool vis[MAXV];
 26 int n;
 27 
 28 void insert(int u, int v)
 29 {
 30     E[EN].v = v;
 31     E[EN].next = head[u];
 32     head[u] = EN++;
 33 }
 34 
 35 bool find(int t)
 36 {
 37     int v;
 38     for(int i = head[t];i != -1 ;i = E[i].next) {
 39         if(vis[ v = E[i].v ])
 40             continue;
 41         vis[v] = true;
 42         if(mat[v] == -1 || find(mat[v])) {
 43             mat[v] = t;
 44             return true;
 45         }
 46     }
 47     return false;
 48 }
 49 inline int MaxMatch() {
 50     int i,num = 0;
 51     clr(mat,-1);
 52     for(i = 0;i < n;i ++) {
 53         clr(vis,false);
 54         num += find(i);
 55     }
 56     return num;
 57 }
 58 
 59 int G[55][55],G1[55][55],G2[55][55];
 60 
 61 int main(void)
 62 {
 63     int r,c;
 64     while (~scanf("%d%d",&r,&c))
 65     {
 66         char s[55];
 67         for(int i=0; i<r; i++)
 68         {
 69             scanf("%s",s);
 70             for(int j=0; j<c; j++)
 71             {
 72                 if ('*' == s[j])
 73                     G[i][j] = 1;
 74                 else
 75                     G[i][j] = 0;
 76             }
 77         }
 78 
 79         EN = 0;
 80         memset(head,-1,sizeof(head));
 81 
 82         n = 0;
 83         int n1,n2;
 84         n1 = 0;
 85         // 横向木板点集
 86         for(int i=0; i<r; i++)
 87         {
 88             for(int j=0; j<c; j++)
 89             {
 90                 if (G[i][j])
 91                 {
 92                     G1[i][j] = n1;
 93                     if (c-1 == j || !G[i][j+1])
 94                         n1++;
 95                 }
 96             }
 97         }
 98 
 99         n2 = 0;
100         // 纵向木板点集
101         for(int i=0; i<c; i++)
102         {
103             for(int j=0; j<r; j++)
104             {
105                 if (G[j][i])
106                 {
107                     G2[j][i] = n2;
108                     if (r-1 == j || !G[j+1][i])
109                         n2++;
110                 }
111             }
112         }
113 
114         // 加边
115         for(int i=0; i<r; i++)
116             for(int j=0; j<c; j++)
117                 if (G[i][j])
118                     insert(G1[i][j],G2[i][j]);
119 
120         n = n1;
121 
122         printf("%d\n",MaxMatch());
123     }
124     return 0;
125 }

 

posted @ 2014-04-01 20:45  辛力啤  阅读(142)  评论(0编辑  收藏  举报