[POJ] 2226 Muddy Fields(二分图最小点覆盖)

题目地址: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\n",hungary()); 

106     

107     return 0;

108 }

 

你可能感兴趣的:(Field)