题目描述
小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏。矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:
行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)
列交换操作:选择矩阵的任意两列,交换这两列(即交换对应格子的颜色)
游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。
对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!!于是小Q决定写一个程序来判断这些关卡是否有解。
输入输出格式
输入格式:
第一行包含一个整数T,表示数据的组数。
接下来包含T组数据,每组数据第一行为一个整数N,表示方阵的大小;接下来N行为一个N*N的01矩阵(0表示白色,1表示黑色)。
输出格式:
包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No。
输入输出样例
输入样例#1:
2 2 0 0 0 1 3 0 0 1 0 1 0 1 0 0
输出样例#1:
No Yes
说明
对于20%的数据,N ≤ 7
对于50%的数据,N ≤ 50
对于100%的数据,N ≤ 200
/* 最终状态是(1,1)(2,2)...(n,n)都有一个点 我们把点看成匹配边的话,就是每行和每列都做到了匹配 换言之就是N个行和N个列都有匹配时,一定能转换成最终状态 所以就如S向每行所对应的点连边,每列所对应的点向T连边 每个1的块就是某行和某列的边 再逆过来转换到初始状态,我们发现交换行本质就是交换S向这两行连的边,所以匹配数不变 同理交换列也是 举个例子来说吧,如果有一行里有两个1,那么我们无论怎么交换行和列这两个一永远在同一行里,匹配数不变 */ #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 100000 int T,n,link[maxn],num,head[maxn]; struct node{ int to,pre; }e[maxn*2]; bool vis[maxn*2]; void Insert(int from,int to){ e[++num].to=to; e[num].pre=head[from]; head[from]=num; } bool dfs(int x){ for(int i=head[x];i;i=e[i].pre){ int to=e[i].to; if(!vis[to]){ vis[to]=1; if(!link[to]||dfs(link[to])){ link[to]=x; return 1; } } } return 0; } int main(){ scanf("%d",&T); while(T--){ memset(link,0,sizeof(link)); memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); memset(e,0,sizeof(e));num=0; scanf("%d",&n); int x; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ scanf("%d",&x); if(x==1)Insert(i,n+j); } int ans=0; for(int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); if(dfs(i))ans++; } if(ans>=n)printf("Yes\n"); else printf("No\n"); } }