1. 程式人生 > >[bzoj1059] [ZJOI2007]矩陣遊戲

[bzoj1059] [ZJOI2007]矩陣遊戲

scrip 通過 如同 ont 大小 格子 add 是不是 char

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

Sample Output

No
Yes

Solution

註意到兩個在同一行或者同一列變換之後必然還處於同一行或同一列,所以這題合法的充要條件就是能不能找到\(n\)個兩兩不同行同列的點。

然後直接二分圖匹配就好了。

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

#define write(x) printf("%d\n",x)

const int maxn = 4e2+10;

struct edge{int to,nxt;}e[maxn*maxn];
int head[maxn],tot,n;

void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}

int match[maxn*2],vis[maxn*2];

int dfs(int x) {
    for(int i=head[x];i;i=e[i].nxt) 
        if(!vis[e[i].to]) {
            vis[e[i].to]=1;
            if(match[e[i].to]==-1||dfs(match[e[i].to])) {
                match[e[i].to]=x,match[x]=e[i].to;
                return 1;   
            }
        }
    return 0;
}

int max_match() {
    memset(match,-1,sizeof match);
    int ans=0;
    for(int i=1;i<=n;i++) {
        if(match[i]!=-1) continue;
        memset(vis,0,sizeof vis);
        if(dfs(i)) ans++;
    }return ans;
}

int main() {
    int T;read(T);
    while(T--) {
        tot=0;memset(head,0,sizeof head);
        int x;read(n);
        for(int i=1;i<=n;i++) 
            for(int j=1;j<=n;j++) {
                read(x);
                if(x) ins(i,j+n);
            }
        if(max_match()==n) puts("Yes");
        else puts("No");
    }
    return 0;
}

[bzoj1059] [ZJOI2007]矩陣遊戲