zoj1654

题解:

对于每一联通的x,y

检点

然后交叉的连边

然后二分图

代码:

#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<algorithm>  
using namespace std;  
const int N=1250;  
int cas,n,m,num,t,x[N][N],y[N][N],f[N],fi[N],ne[N],zz[N],match[N],r,c;  
char s[N][N];  
void jb(int x,int y)  
{  
    zz[++num]=y;  
    ne[num]=fi[x];  
    fi[x]=num;  
}  
void build()  
{   
    r=1,c=1;  
    for (int i=0;i<n;i++)  
     for (int j=0;j<m;j++)  
      {  
        if (s[i][j]!='#'&&!x[i][j])
         {  
            for (int k=j;s[i][k]!='#'&&k<m;k++){x[i][k]=r;}  
            r++;  
         }  
        if (s[i][j]!='#'&&!y[i][j])
         {  
            for (int k=i;s[k][j]!='#'&&k<n;k++){y[k][j]=c;}  
            c++;  
         }  
      }   
    for (int i=0;i<n;i++)  
     for (int j=0;j<m;j++)
      if (s[i][j]=='o'&&x[i][j]&&y[i][j])jb(x[i][j],y[i][j]);  
}  
int dfs(int x)
{
    for (int i=fi[x];i;i=ne[i])
     if (!f[zz[i]])
      {
          f[zz[i]]=1;
          if (!match[zz[i]]||dfs(match[zz[i]]))
           {
               match[zz[i]]=x;
               return 1;
           }
      }
    return 0;  
}
int main()  
{  
    scanf("%d",&t); 
    while (t--)  
     {  
            memset(x,0,sizeof x);  
        memset(y,0,sizeof y);  
        memset(fi,0,sizeof fi);  
        memset(match,0,sizeof match);    
        num=0;
        scanf("%d%d",&n,&m);  
        for (int i=0;i<n;i++)scanf("%s",s[i]);  
            build();  
            printf("Case :%d
",++cas);
        int ans=0;  
        for (int i=1;i<=r;i++)
         {  
            memset(f,0,sizeof f);  
               ans+=dfs(i); 
          }  
        printf("%d
",ans); 
     }  
}  
原文地址:https://www.cnblogs.com/xuanyiming/p/8260324.html