1. 程式人生 > >洛谷P1129 [ZJOI2007]矩陣遊戲

洛谷P1129 [ZJOI2007]矩陣遊戲

namespace color 整數 iostream 每次 右下角 -a 輸入輸出 關卡

P1129 [ZJOI2007]矩陣遊戲

題目描述

小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"); } }

洛谷P1129 [ZJOI2007]矩陣遊戲