题目传送门
题目描述
小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏。矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:
行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)
列交换操作:选择矩阵的任意两列,交换这两列(即交换对应格子的颜色)
游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。
对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!!于是小Q决定写一个程序来判断这些关卡是否有解。
输入输出格式
输入格式:
第一行包含一个整数T,表示数据的组数。
接下来包含T组数据,每组数据第一行为一个整数N,表示方阵的大小;接下来N行为一个N*N的01矩阵(0表示白色,1表示黑色)。
输出格式:
包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No。
输入输出样例
说明
对于20%的数据,N ≤ 7
对于50%的数据,N ≤ 50
对于100%的数据,N ≤ 200
题解:
一道不太好建模的二分图...
首先我们可以发现直接把格子当做点是不可做的。所以我们考虑把每一列当做一个点,把每一行当做一个点。考虑末状态,可以看做第i行向第i列连了一条匹配边。行交换操作可以看做匹配边的交换。
比如(1,4)、(2,3)是黑格子的话可以看做1->4,2->3连了匹配边(注意,箭头左右分属不同集合,即使数值相同,代表的含义也不同,在代码中的编号也是不同的)。那么交换第一第二行后黑格子就变成了(1,3)、(2,4),匹配边为1->3,2->4。可以发现交换x,y两行就是交换x,y的匹配边。交换列同理。
所以我们可以得出的一个结论就是如果想要达到最终状态,那么一开始最大匹配数就要等于n.
可以用网络流求最大匹配数。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #define LL long long 7 #define RI register int 8 using namespace std; 9 const int INF = 0x7ffffff ; 10 const int N = 200 + 10 ; 11 const int M = 1e7 + 10 ; 12 13 inline int read() { 14 int k = 0 , f = 1 ; char c = getchar() ; 15 for( ; !isdigit(c) ; c = getchar()) 16 if(c == '-') f = -1 ; 17 for( ; isdigit(c) ; c = getchar()) 18 k = k*10 + c-'0' ; 19 return k*f ; 20 } 21 struct Edge { 22 int to, next, flow ; 23 }e[M] ; 24 int n, s, t, ansf, cnt = 1 ; int head[N<<1], dep[N<<1] ; 25 inline void add_edge(int x,int y,int ff) { 26 e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt, e[cnt].flow = ff ; 27 e[++cnt].to = x, e[cnt].next = head[y], head[y] = cnt, e[cnt].flow = 0 ; 28 } 29 30 inline bool F_bfs() { 31 memset(dep,0,sizeof(dep)) ; 32 queue<int>q ; q.push(s) ; dep[s] = 1 ; 33 while(!q.empty()) { 34 int x = q.front() ; q.pop() ; 35 for(int i=head[x];i;i=e[i].next) { 36 int y = e[i].to ; if(dep[y] || !e[i].flow) continue ; 37 dep[y] = dep[x]+1 ; q.push(y) ; 38 } 39 } 40 return dep[t] ; 41 } 42 int F_dfs(int x,int minflow) { 43 if(x == t || !minflow) return minflow ; 44 int fflow = 0 ; 45 for(int i=head[x];i;i=e[i].next) { 46 int y = e[i].to ; if(dep[y] != dep[x]+1 || !e[i].flow) continue ; 47 int temp = F_dfs(y,min(minflow,e[i].flow)) ; 48 fflow += temp, minflow -= temp ; 49 e[i].flow -= temp, e[i^1].flow += temp ; 50 if(!minflow) break ; 51 } 52 return fflow ; 53 } 54 55 56 inline void solve() { 57 n = read() ; memset(head,0,sizeof(head)) ; ansf = 0 ; s = (n<<1)+1, t = s+1 ; 58 for(int i=1;i<=n;i++) { 59 add_edge(s,i,1) ; add_edge(i+n,t,1) ; 60 for(int j=1;j<=n;j++) { 61 bool x = read() ; 62 if(x) { 63 add_edge(i,j+n,1) ; 64 } 65 } 66 } 67 while(F_bfs()) ansf += F_dfs(s,INF) ; 68 if(ansf == n) printf("Yes\n") ; else printf("No\n") ; 69 } 70 71 int main() { 72 int t = read() ; 73 while(t--) solve() ; 74 return 0 ; 75 }