<题目链接>
题目大意:
给你一张图,图中有 '*' , '.' 两点,现在每次覆盖相邻的两个 '#' ,问最多能够覆盖几次。
解题分析:
无向图二分匹配的模板题,每个'#'点与周围四个方向的'#'建立匹配关系,然后用匈牙利跑一遍,因为匹配的两点各会进行相互匹配一次,所以最大匹配数为ans/2。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int N=600+10; //本题数据中'#'数量较少,开到600都能AC 7 char mpa[605][605]; 8 int n,vN,vM; 9 int g[N][N],cnt[605][605],vis[N],match[N]; 10 bool dfs(int x){ 11 for(int i=1;i<=vM;i++){ 12 if(g[x][i]&&!vis[i]){ 13 vis[i]=1; 14 if(match[i]==-1||dfs(match[i])){ 15 match[i]=x; 16 return true; 17 } 18 } 19 } 20 return false; 21 } 22 int Hungary(){ 23 int ans=0; 24 memset(match,-1,sizeof(match)); 25 for(int i=1;i<=vN;i++){ 26 memset(vis,0,sizeof(vis)); 27 if(dfs(i))ans++; 28 } 29 return ans; 30 } 31 int main(){ 32 int T;scanf("%d",&T); 33 int ncase=0; 34 while(T--){ 35 scanf("%d",&n); 36 int pos=0; 37 for(int i=1;i<=n;i++){ 38 scanf("%s",mpa[i]+1); 39 for(int j=1;j<=n;j++) 40 if(mpa[i][j]=='#')cnt[i][j]=++pos; //给所有的'#'分配编号 41 } 42 memset(g,0,sizeof(g)); 43 //将该点与其周围四个方向的'#'都建立匹配关系 44 for(int i=1;i<=n;i++){ 45 for(int j=1;j<=n;j++){ 46 if(mpa[i][j]!='#')continue; 47 if(i-1>=1&&mpa[i-1][j]=='#')g[cnt[i][j]][cnt[i-1][j]]=1; 48 if(j-1>=1&&mpa[i][j-1]=='#')g[cnt[i][j]][cnt[i][j-1]]=1; 49 if(i+1<=n&&mpa[i+1][j]=='#')g[cnt[i][j]][cnt[i+1][j]]=1; 50 if(j+1<=n&&mpa[i][j+1]=='#')g[cnt[i][j]][cnt[i][j+1]]=1; 51 } 52 } 53 vN=vM=pos; 54 int ans=Hungary(); //求出最大匹配数 55 printf("Case %d: %d ",++ncase,ans/2); //因为匹配的两点会相互各进行一次匹配,所以这里要除以2 56 } 57 return 0; 58 }
2018-11-14