POJ - 2226 Muddy Fields (最小顶点覆盖)

*.*.
.***
***.
..*.

题意:有一个N*M的像素图,现在问最少能用几块1*k的木条覆盖所有的 * 点,k为>=1的任意值。

分析:和小行星那题很像。小行星那题是将一整行(列)看作一个点,但本题一行或一列内可能有多个连通块。所以先根据像素图统计出总的行列连通块的个数。

将行连通块视作X部;列连通块视作Y部;连接一对行列连通块的*像素点视作边,问题转化为了用最少的边去覆盖所有的点,即最小点覆盖。

建图之后求二分图的最小点覆盖。

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn = 1300;
int N;
struct Edge{
    LL val;
    int to,next;
}edges[maxn<<2];
int head[maxn],tot;
int linker[maxn];
bool used[maxn];

void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
}

void AddEdge(int u,int v, LL val)
{
    edges[tot].val = val;
    edges[tot].to = v;
    edges[tot].next = head[u];
    head[u] = tot++;
}

bool dfs(int u){
    int v;
    for(int i=head[u];~i;i = edges[i].next){
        v = edges[i].to;
        if(!used[v]){
            used[v]=true;
            if(linker[v]==-1||dfs(linker[v])){
                linker[v]=u;
                return true;
            }
        }
    }
    return false;
}

int hungary(){
    int u;
    int res=0;
    memset(linker,-1,sizeof(linker));
    for(u=1;u<=N;u++){
        memset(used,0,sizeof(used));
        if(dfs(u)) res++;
    }
    return res; 
}

int idx[60][60],idy[60][60];
char G[maxn][maxn];

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int M;
    while(scanf("%d%d",&N,&M)==2){
        init();
        for(int i=1;i<=N;++i){
            scanf("%s",G[i]+1);
        }
        memset(idx,0,sizeof(idx));
        memset(idy,0,sizeof(idy));
        int cnt1=0,cnt2 = 0;
        for(int i=1;i<=N;++i){
            for(int j=1;j<=M;++j){
                if(G[i][j]!='*') continue;
                if(idx[i][j-1]) idx[i][j] = idx[i][j-1];
                else idx[i][j] = ++cnt1;
                if(idy[i-1][j]) idy[i][j] = idy[i-1][j];
                else idy[i][j] = ++cnt2;
            }
        }
        for(int i=1;i<=N;++i){
            for(int j=1;j<=M;++j){
                if(G[i][j]=='*')
                    AddEdge(idx[i][j],idy[i][j],0);
            }
        }
        N = cnt1;
        printf("%d\n",hungary());
    }
    return 0;
}

 


posted @ 2018-08-20 21:17  xiuwenL  阅读(114)  评论(0编辑  收藏  举报