UVALive 5903 Piece it together 二分匹配,拆点 难度:1
对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; }