Description
小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏。矩阵游戏在一个N
*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:行交换操作:选择
矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵的任意行列,交换这两列(即交换
对应格子的颜色)游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑
色。对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!!于是小Q决定写一个程
序来判断这些关卡是否有解。
Input
第一行包含一个整数T,表示数据的组数。接下来包含T组数据,每组数据第一行为一个整数N,表示方阵的大
小;接下来N行为一个N*N的01矩阵(0表示白色,1表示黑色)。
Output
输出文件应包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No。
Sample Input
2
2
0 0
0 1
3
0 0 1
0 1 0
1 0 0
2
0 0
0 1
3
0 0 1
0 1 0
1 0 0
Sample Output
No
Yes
【数据规模】
对于100%的数据,N ≤ 200
Yes
【数据规模】
对于100%的数据,N ≤ 200
HINT
Source
对于这道题的交换方式我们会发现如果给你一个已经达到要求的矩阵,那么在对角线上的点永远不可能移动到同一行或者同一列。
所以说能够达到题目要求的矩阵一定有n个互相不为同行或列的点,而这个问题可以通过二分图匹配解决。
把n行设成n个点把n列设成n个点,对于(i,j)为黑就在i行,j列连一条边即可。
http://www.lydsy.com/JudgeOnline/problem.php?id=1059
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=405; int yd,s; struct X { int v,sy,f,n; }x[90005]; int pre[N],cs[N],q[N]; bool vis[N]; void add(int u,int v,int sy) { x[++s].v=v; x[s].n=x[u].f; x[x[u].f=s].sy=sy; } int dfs(int u,int a) { if(!a||u==yd+1) return a; int fl=0,f; for(int&i=pre[u];i;i=x[i].n) if(cs[u]+1==cs[x[i].v]&&(f=dfs(x[i].v,min(a,x[i].sy)))) { fl+=f; a-=f; x[i].sy-=f; x[i^1].sy+=f; } return fl; } bool bfs() { memset(vis,0,sizeof(vis)); vis[q[0]=yd]=1; int t=0,w=0; for(;t<=w;++t) { for(int i=x[q[t]].f;i;i=x[i].n) if(x[i].sy&&!vis[x[i].v]) { vis[x[i].v]=1; cs[x[i].v]=cs[q[t]]+1; q[++w]=x[i].v; } } return vis[yd+1]; } int main() { int t; scanf("%d",&t); while(t--) { memset(x,0,sizeof(x)); int n,ans=0; scanf("%d",&n); yd=2*n+1; s=1; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) { int a; scanf("%d",&a); if(a) add(i,n+j,1),add(n+j,i,0); } for(int i=1;i<=n;++i) { add(yd,i,1); add(i,yd,0); add(n+i,yd+1,1); add(yd+1,n+i,1); } while(bfs()) { for(int i=1;i<=yd+1;++i) pre[i]=x[i].f; ans+=dfs(yd,1000000000); } ans==n?printf("Yes\n"):printf("No\n"); } return 0; }