题目地址:http://poj.org/problem?id=2226
二分图的题目关键在于建图。因为“*”的地方只有两种木板覆盖方式:水平或竖直,所以运用这种方式进行二分。首先按行排列,算出每个"*"的序号xi,再按列排序,算出序号yi。
从X集合向Y集合连边。G[xi][yi]=1; 然后就是求二分图的最小顶点覆盖。因为二分图最小点覆盖=最大匹配数。所以匈牙利算法求一下最大匹配就可以了。
1 #include<cstdio> 2 #include<iostream> 3 #include<string.h> 4 #include<algorithm> 5 #include<math.h> 6 #include<stdbool.h> 7 #include<time.h> 8 #include<stdlib.h> 9 #include<set> 10 #include<map> 11 #include<stack> 12 #include<queue> 13 #include<vector> 14 using namespace std; 15 #define clr(x,y) memset(x,y,sizeof(x)) 16 #define sqr(x) ((x)*(x)) 17 #define rep(i,a,b) for(int i=(a);i<=(b);i++) 18 #define LL long long 19 #define INF 0x3f3f3f3f 20 #define A first 21 #define B second 22 #define PI acos(-1.0) 23 const int N=1000+131; 24 int n,m,k,k1,k2,f[N],g[N][N],c1[N][N],c2[N][N],link[N],flag[N][N]; 25 26 void init() 27 { 28 clr(f,0); 29 clr(g,0); 30 clr(link,-1); 31 clr(flag,0); 32 clr(c1,0); 33 clr(c2,0); 34 k1=0;k2=0; 35 } 36 37 bool find(int x) 38 { 39 for(int i=1;i<=k2;i++) { 40 if(!f[i] && g[x][i]) { 41 f[i]=1; 42 if(link[i]==-1 || find(link[i])) { 43 link[i]=x; 44 return true; 45 } 46 } 47 } 48 49 return false; 50 } 51 52 int hungary() 53 { 54 int ans=0; 55 for(int i=1;i<=k1;i++) { 56 clr(f,0); 57 if(find(i)) ans++; 58 } 59 return ans; 60 } 61 62 int main() 63 { 64 int u,v; 65 char a[100]; 66 67 init(); 68 scanf("%d%d",&m,&n); 69 getchar(); 70 for(int i=1;i<=m;i++) { 71 scanf("%s",a+1); 72 for(int j=1;j<=n;j++) { 73 if(a[j]=='*') flag[i][j]=1; 74 } 75 } 76 77 for(int i=1;i<=m;i++) { 78 for(int j=1;j<=n;j++) { 79 if(!flag[i][j]) continue; 80 if(!flag[i][j-1]){ 81 c1[i][j]=++k1; 82 } else { 83 c1[i][j]=k1; 84 } 85 } 86 } 87 88 for(int i=1;i<=n;i++) { 89 for(int j=1;j<=m;j++) { 90 if(!flag[j][i]) continue; 91 if(!flag[j-1][i]) { 92 c2[j][i]=++k2; 93 } else { 94 c2[j][i]=k2; 95 } 96 } 97 } 98 99 for(int i=1;i<=m;i++){ 100 for(int j=1;j<=n;j++) { 101 g[c1[i][j]][c2[i][j]]=1; 102 } 103 } 104 105 printf("%d ",hungary()); 106 107 return 0; 108 }