码迷,mamicode.com
首页 > 其他好文 > 详细

POJ [P3020] Antenna Placement

时间:2018-01-12 20:28:47      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:顶点   象棋   地图   code   name   cst   信号   main   国际   

二分图匹配求最小边覆盖

建图方法中的黑白染色法,题目中说信号可以覆盖相邻两个块,那么我们可以将给定的地图染成国际象棋棋盘的样子,一个黑格可以与周围的四个白格共用信号,对于城市,从每一个黑格出发,向其周围的白格连边,那么这就是一个二分图,我们的把城市抽象成了点,所以我们的目的是找到最少的边覆盖所有的点,即最小边覆盖。
在二分图中,最小边覆盖=顶点数-最大匹配数。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int init(){
    int rv=0,fh=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') fh=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        rv=(rv<<1)+(rv<<3)+c-'0';
        c=getchar();
    }
    return fh*rv;
}
int T,n,m,g[405][5],rs[50][50],clr[50][50],dx[4]={-1,0,0,1},dy[4]={0,-1,1,0},match[405];
bool f[405];
char ma[50][50];
bool hungarian(int u){
    for(int i=1;i<=g[u][0];i++){
        int v=g[u][i];
        if(!f[v]){
            f[v]=1;
            if(!match[v]||hungarian(match[v])){
                match[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
int main(){
    T=init();
    while(T--){
        n=init();m=init();
        memset(ma,0,sizeof(ma));
        memset(rs,0,sizeof(rs));
        memset(clr,0,sizeof(clr));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(j==1) rs[i][j]=!rs[i-1][j];
                else rs[i][j]=!rs[i][j-1];
                scanf(" %c ",&ma[i][j]);
            }
        }
        int blk=0,wit=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(ma[i][j]=='*'){
                    if(rs[i][j]) clr[i][j]=++wit;
                    else clr[i][j]=++blk;
                }else clr[i][j]=0;
            }
        }
        memset(g,0,sizeof(g));
        memset(match,0,sizeof(match));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(clr[i][j]&&rs[i][j]){
                    int u=clr[i][j];
                    for(int k=0;k<=3;k++){
                        int x=i+dx[k],y=j+dy[k];
                        if(clr[x][y]) g[u][++g[u][0]]=clr[x][y];
                    }
                }
            }
        }
        int ans=0;
        for(int i=1;i<=wit;i++){
            memset(f,0,sizeof(f));
            if(hungarian(i)) ans++;
        }
        cout<<wit+blk-ans<<endl;
        //cout<<ans<<endl;
    }
}

POJ [P3020] Antenna Placement

标签:顶点   象棋   地图   code   name   cst   信号   main   国际   

原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/8277458.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!