题目描述
小QQ是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏。矩阵游戏在一个N imes NN×N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:
行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)
列交换操作:选择矩阵的任意两列,交换这两列(即交换对应格子的颜色)
游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。
对于某些关卡,小QQ百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!于是小QQ决定写一个程序来判断这些关卡是否有解。
输入输出格式
输入格式:
第一行包含一个整数TT,表示数据的组数。
接下来包含TT组数据,每组数据第一行为一个整数NN,表示方阵的大小;接下来NN行为一个N imes NN×N的0101矩阵(00表示白色,11表示黑色)。
输出格式:
包含TT行。对于每一组数据,如果该关卡有解,输出一行YesYes;否则输出一行NoNo。
输入输出样例
说明
对于20\%20%的数据,N ≤ 7N≤7
对于50\%50%的数据,N ≤ 50N≤50
对于100\%100%的数据,N ≤ 200N≤200
题解
前置知识二分图
此题比较有代表性,思维难度较高,建模后代码很简单。
这题的最终目标是要让主对角线上都是黑格,即对于每一个x∈[1,N],满足(x,x)。
于是此时问题就转化为找N个横纵坐标相同的点,于是我们可以这样建模:
我们将行作为左集合,列作为右集合,每个点就是一条边,而交换行就是交换点的顺序
这样一来,我们就很容易发现只要能实现N个匹配,就一定可以通过交换点来达成目标
然后我们就可以运用二分图匹配的模板解决这道题了
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int INF=1e9+7,MAXN=201,MAXM=MAXN*MAXN; 5 int T,N; 6 int head[MAXN],to[MAXM],nxt[MAXM],tp; 7 inline void add(int x,int y){ 8 nxt[++tp]=head[x]; 9 head[x]=tp; 10 to[tp]=y; 11 } 12 int used[MAXN],match[MAXN]; 13 bool dfs(int x){ 14 for(int i=head[x];i;i=nxt[i]){ 15 if(!used[to[i]]){ 16 used[to[i]]=1; 17 if(!match[to[i]]||dfs(match[to[i]])){ 18 match[to[i]]=x; 19 return 1; 20 } 21 } 22 } 23 return 0; 24 } 25 int main(){ 26 scanf("%d",&T); 27 while(T--){ 28 scanf("%d",&N); 29 tp=0; 30 memset(head,0,sizeof(head)); 31 memset(match,0,sizeof(match)); 32 for(int i=1;i<=N;i++){ 33 for(int j=1;j<=N;j++){ 34 int ii; 35 scanf("%d",&ii); 36 if(ii){ 37 add(i,j); 38 } 39 } 40 } 41 int flag=1; 42 for(int i=1;i<=N&&flag;i++){ 43 memset(used,0,sizeof(used)); 44 flag=dfs(i); 45 } 46 if(flag){ 47 puts("Yes"); 48 }else{ 49 puts("No"); 50 } 51 } 52 return 0; 53 }