bzoj 1059: [ZJOI2007]矩阵游戏 (匈牙利算法)
1059: [ZJOI2007]矩阵游戏
Time Limit: 10 Sec Memory Limit: 162 MB Submit: 5251 Solved: 2512 [Submit][Status][Discuss]
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 【数据规模】 对于100%的数据,N ≤ 200
思路:
纠结了一下建图,由于每个黑点可以按照行换,也可以按照列换。所以我建了一个1..n到1..2n的二分图做匹配。
左边集合是n个对角线上的点,右边集合是行号+列号。
但是每次匹配的时候,一个对角线上的点会同时消耗到匹配的行号和列号。。感觉不是很对啊。。。
实际上发现,我们只需要建立一个n到n的二分图就行了。
原因是,如果有解,那么只需要行或者列的一种变换,就可以达到规定的图案。
比如现在(2,5)是1,(2,2)和(5,5)是0,我们只需要连一条边表示(2,5)可以换到(2,2)即可,不需要连表示(2,5)可以换到(5,5)的边
原因是,如果(2,5)换到(5,5),那么(2,2)也跟着换到了(5,2),我们不考虑之前的(2,2)是什么,被换之后的(2,2)必须是1才符合题意,也就是换之前的(5,2)必须是1.
既然(5,2)是1,那么从(5,2)换到(5,5)即可符合条件。
/* ***********************************************
Author :111qqz
Created Time :2017年10月31日 星期二 21时54分23秒
File Name :1059.cpp
************************************************ */
#include <bits/stdc++.h>
#define PB push_back
#define fst first
#define sec second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ms(a,x) memset(a,x,sizeof(a))
typedef long long LL;
#define pi pair < int ,int >
#define MP make_pair
using namespace std;
const double eps = 1E-8;
const int dx4[4]={1,0,0,-1};
const int dy4[4]={0,-1,1,0};
const int inf = 0x3f3f3f3f;
const int N=200*2+7;
int Link[N];
bool vis[N];
vector<int>edge[N];
int n;
bool Find( int u)
{
int siz = edge[u].size();
for ( int i = 0 ; i < siz ; i++)
{
int v = edge[u][i];
if (vis[v]) continue;
vis[v] = true;
if (Link[v]==-1||Find(Link[v]))
{
Link[v] = u;
return true;
}
}
return false;
}
bool hungry( int n)
{
int ret = 0;
ms(Link,-1);
for ( int i = 1 ; i <= n ; i++)
{
ms(vis,false);
if (Find(i)) ret++;
else break;
}
return ret==n;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("./in.txt","r",stdin);
#endif
int T;
cin>>T;
while (T--)
{
cin>>n;
for ( int i = 1 ; i <= n ; i++) edge[i].clear();
int x;
for ( int i = 1 ; i <= n ; i++)
{
for ( int j = 1 ; j <= n ; j++)
{
scanf("%d",&x);
if (x==1)
{
edge[i].PB(j);
}
}
}
if (hungry(n))
puts("Yes");
else puts("No");
}
#ifndef ONLINE_JUDGE
fclose(stdin);
#endif
return 0;
}