poj 3020 Antenna Placement (最小边覆盖)

题目具体讲什么没怎么看,本质就是说给一个n*m的图,里面有*和o,现在让你用1*2或2*1的矩阵覆盖图中的*,求最少需要多少个。


建图:对于相邻的两个*,连一条边,然后将一个*,拆做两个,分别属于X、Y集合,得到一个二分图。对于该二分图,边即代表用来覆盖的矩阵,问题转化为用最少的边覆盖所有的点。对于已经匹配的点,用匹配的边去覆盖就好了。剩下的点个数=顶点总数-最大匹配数*2.各自需要一个来覆盖,因此总共需要的最少的边数为顶点总数-最大匹配数


注意到,这里的二分图是拆点后形成的一个无向图(边是对称出现的),因此匹配的时候,同一个点会被匹配两次。因此实际上的最大匹配数为所求得的匹配数的一半。


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#include<vector>
#include<cmath>
using namespace std;
#define N 50
bool Map[550][550],T[550];
int Left[550],M[50][50],mov[4][2]={{1,0},{-1,0},{0,-1},{0,1}};
int match(int u,int n){
    for(int v=1;v<=n;++v){
        if(Map[u][v]&&!T[v]){
            T[v]=1;
            if(!Left[v]||match(Left[v],n)){
                Left[v]=u;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    int t,cnt,i,j,n,m,k;
    cin>>t;
    while(t--){
        cnt=0;
        scanf("%d%d",&n,&m);
        getchar();
        memset(M,0,sizeof(M));
        memset(Map,0,sizeof(Map));
        for(i=0;i<n;++i)
            for(j=0;j<=m;++j) if(getchar()=='*') M[i][j]=++cnt;

        for(i=0;i<n;++i)
            for(j=0;j<m;++j)
                if(M[i][j]){
                    for(k=0;k<4;++k){
                        int ii=i,jj=j;
                        ii+=mov[k][0];
                        jj+=mov[k][1];
                        if(ii>=0&&jj>=0&&ii<n&&jj<m&&M[ii][jj]) Map[M[i][j]][M[ii][jj]]=1;
                    }
                }
        int ans=0;
        memset(Left,0,sizeof(Left));
        for(i=1;i<=cnt;++i){
            for(j=1;j<=cnt;++j) T[j]=0;
            ans+=match(i,cnt);
        }
        printf("%d\n",cnt-ans/2);
    }
    return 0;
}


你可能感兴趣的:(poj 3020 Antenna Placement (最小边覆盖))