UVALive 5903 Piece it together 二分匹配,拆点 难度:1

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3914

对L研究可以发现

相当于黑-横白,黑-纵白,每个黑白都要被匹配到,其中黑的横纵各两次,

很自然的想到拆点,黑点拆成专门和横白连接的,专门和纵白连接的,

如果2*黑==白数,运行一次二分匹配算法,匹配数==白数则为可行,剩下的都不可行

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
char maz[600][601];
int ind[600][600];
int n,m;
bool inmaz(int x,int y){return 0<=x&&x<n&&0<=y&&y<m;}
struct pnt{
        int x,y;
        pnt(){x=y=0;}
        pnt(int x,int y){this->x=x;this->y=y;}
};
pnt pw[600*600],pb[600*600];
int lenw,lenb;
int e[2*600*600][8];
int len[2*600*600];

int mch[2*600*600];
bool used[2*600*600];

bool dfs(int s){
        used[s]=true;
        for(int i=0;i<len[s];i++){
                int t=e[s][i];
                if(mch[t]==-1||(!used[mch[t]]&&dfs(mch[t]))){
                        mch[t]=s;
                        mch[s]=t;
                        return true;
                }
        }
        return false;
}

int match(){
        memset(mch,-1,sizeof(int)*2*lenw);
        int res=0;
        for(int i=0;i<lenw*2;i++){
                if(mch[i]==-1){
                        memset(used,false,2*lenw);
                        if(dfs(i)){
                                res++;
                        }
                }
        }
        return res;
}

int main(){
        int T;
        scanf("%d",&T);
        while(T--){
                scanf("%d%d",&n,&m);
                lenb=lenw=0;
                memset(len,0,sizeof(len));
                memset(ind,0,sizeof(ind));
                for(int i=0;i<n;i++)scanf("%s",maz[i]);
                for(int i=0;i<n;i++){
                        for(int j=0;j<m;j++){
                                if(maz[i][j]=='W'){
                                        ind[i][j]=lenw;
                                        pw[lenw++]=pnt(i,j);
                                }
                                else if(maz[i][j]=='B'){
                                        ind[i][j]=lenb;
                                        pb[lenb++]=pnt(i,j);
                                }
                        }
                }
                if(lenw!=lenb*2){
                        puts("NO");
                        continue;
                }
                for(int i=0;i<lenb;i++){
                        int x=pb[i].x,y=pb[i].y;
                        for(int j=0;j<2;j++){
                                int txj=x+dx[j],tyj=y+dy[j];
                                if(!inmaz(txj,tyj)||maz[txj][tyj]!='W')continue;
                                int indj=ind[txj][tyj],hor=lenw+2*i+1;

                                e[indj][len[indj]++]=hor;
                                e[hor][len[hor]++]=indj;
                        }
                        for(int k=2;k<4;k++){
                                int txk=x+dx[k],tyk=y+dy[k];
                                if(!inmaz(txk,tyk)||maz[txk][tyk]!='W')continue;
                                int indk=ind[txk][tyk],gra=lenw+2*i;
                                e[indk][len[indk]++]=gra;
                                e[gra][len[gra]++]=indk;
                        }
                }
                int res=match();
                if(res!=lenw)puts("NO");
                else puts("YES");
        }
        return 0;
}

  

转载于:https://www.cnblogs.com/xuesu/p/4328913.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值