[ZJOI2007]矩阵游戏【bzoj1059/洛谷1129】/ [HEOI2016/TJOI2016]游戏
小QQ是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏。矩阵游戏在一个N \times NN×N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:
行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)
列交换操作:选择矩阵的任意两列,交换这两列(即交换对应格子的颜色)
游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。
对于某些关卡,小QQ百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!于是小QQ决定写一个程序来判断这些关卡是否有解。
目标状态要求矩阵的主对角线上的格子均为黑色。
即是(1,1),(2,2),(3,3)......(n,n)皆匹配;
如果原图满足每行和每列都匹配,那么通过交换,一定可以换成上面这种情况。
所以拆行和列跑一个最大二分图匹配,并判断匹配数是否等于n即可。
代码见
#include<bits/stdc++.h> #define re register int #define maxn 200+5 using namespace std; int t,n; int ma[maxn][maxn]; inline int read(){ int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')f=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } return x*f; } int ans,match[maxn]; bool ed[maxn][maxn],vis[maxn]; bool dfs(int x){ for(re i=1;i<=n;i++) if(!vis[i]&&ed[x][i]){ vis[i]=true; if(!match[i]||dfs(match[i])) { match[i]=x; return true; } } return false; } int main() { ios::sync_with_stdio(false); t=read(); while(t--) { ans=0; memset(match,0,sizeof(match)); memset(ed,false,sizeof(ed)); n=read(); for(re i=1;i<=n;i++) for(re j=1;j<=n;j++) ed[i][j]=read(); for(re i=1;i<=n;i++) { memset(vis,false,sizeof(vis)); ans+=dfs(i); } if(ans==n) cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }
[HEOI2016/TJOI2016]游戏
在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂。简单的说,这个游戏就是在一张地图上放上若干个炸弹,看是否能炸到对手,或者躲开对手的炸弹。在玩游戏的过程中,小H想到了这样一个问题:当给定一张地图,在这张地图上最多能放上多少个炸弹能使得任意两个炸弹之间不会互相炸到。炸弹能炸到的范围是该炸弹所在的一行和一列,炸弹的威力可以穿透软石头,但是不能穿透硬石头。给定一张n*m的网格地图:其中*代表空地,炸弹的威力可以穿透,可以在空地上放置一枚炸弹。x代表软石头,炸弹的威力可以穿透,不能在此放置炸弹。#代表硬石头,炸弹的威力是不能穿透的,不能在此放置炸弹。例如:给出1*4的网格地图*xx*,这个地图上最多只能放置一个炸弹。给出另一个1*4的网格地图*x#*,这个地图最多能放置两个炸弹。现在小H任意给出一张n*m的网格地图,问你最多能放置多少炸弹。
显然 这道题和上面的题极为相像。
需要处理的是把联通的序列(包括空地和软石头)行和列分别处理,进行二分图匹配。
#include<bits/stdc++.h> #define re register int #define maxn 50+5 #define maxn1 2500+5 using namespace std; int n,m; int cnt,tot; char ma[maxn][maxn]; int row[maxn][maxn],col[maxn][maxn]; struct edge{ int nex,to; }ed[maxn1]; int head[maxn1]; inline int read(){ int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')f=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } return x*f; } inline void write(int x){ if(x<0){ putchar('-'); x=-x; } if(x>9) write(x/10); putchar(x%10+'0'); } int ans,match[maxn1]; bool vis[maxn1]; bool dfs(int x){ for(re e=head[x],v;e;e=ed[e].nex) { if(!vis[v=ed[e].to]) { vis[v]=true; if(!match[v]||dfs(match[v])) { match[v]=x; return true; } } } return false; } void add(int x,int y) { ed[++cnt].nex=head[x]; ed[cnt].to=y; head[x]=cnt; } char get(){ char ch; while((ch=getchar())!='#'&&ch!='*'&&ch!='x'); return ch; } int main() { ios::sync_with_stdio(false); n=read(); m=read(); ; for(re i=1;i<=n;i++) for(re j=1;j<=m;j++) ma[i][j]=get(); for(re i=1;i<=n;i++) for(re j=1;j<=m;j++){ if(ma[i][j]=='#') continue; if(j==1||ma[i][j-1]=='#') tot++; row[i][j]=tot; } for(re i=1;i<=m;i++) for(re j=1;j<=n;j++){ if(ma[j][i]=='#') continue; if(j==1||ma[j-1][i]=='#') tot++; col[j][i]=tot; } for(re i=1;i<=n;i++) for(re j=1;j<=m;j++) { if(ma[i][j]!='*') continue; add(row[i][j],col[i][j]); } for(re i=1;i<=tot;i++) { memset(vis,false,sizeof(vis)); ans+=dfs(i); } write(ans); return 0; }