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 }