POJ 2226 二分图最小覆盖

题意:
这里写图片描述
这里写图片描述

思路:
把横着的连通块放在一个集合 竖着的放在一个集合

如果有交 就连边
求最小覆盖即可 (数值上等于最大匹配)

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 2555*2555
int n,m,first[2555],next[N],v[N],tot,cnt,change[55][55],changea[55][55],vis[2555],matched[2555],ans;
char a[55][55];
void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
bool dfs(int x){
    for(int i=first[x];~i;i=next[i]){
        if(!vis[v[i]]){
            vis[v[i]]=1;
            if(!matched[v[i]]||dfs(matched[v[i]])){
                matched[v[i]]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main(){
    memset(first,-1,sizeof(first));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        getchar();
        for(int j=1;j<=m;j++)
            a[i][j]=getchar();
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]=='*'){
                if(a[i][j-1]=='*')
                    changea[i][j]=changea[i][j-1];
                else changea[i][j]=++cnt;
            }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]=='*'){
                if(a[i-1][j]=='*')
                    change[i][j]=change[i-1][j];
                else change[i][j]=++cnt;
                add(changea[i][j],change[i][j]);
            }
    for(int i=1;i<=cnt;i++){
        memset(vis,0,sizeof(vis));
        if(dfs(i))ans++;
    }
    printf("%d
",ans);
}

这里写图片描述

原文地址:https://www.cnblogs.com/SiriusRen/p/6532207.html