[bzoj1059][ZJOI2007]矩阵游戏_二分图最大匹配

矩阵游戏 bzoj-1059 ZJOI-2007

题目大意:给定一个n*n的棋盘,上面有一些格子被染黑,剩下都是白色。你每次可以交换两列或者两行,问你能否通过一系列操作使得棋盘的主对角线上的格子全是黑色。

注释:$1le nle 200$。


想法

我们发现一个小性质,就是两个格子如果同行那么无论如何操作他们都同行。如果同列那么无论任何时刻他们都同列。

这样的话我们就是要找到每行每列都需要有黑格子。

我们将行和列抽象成点直接跑匈牙利判断一下最大匹配是不是n即可。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 210 
using namespace std;
int fr[N<<1]; bool line[N][N<<1],used[N<<1];
int a[N][N];
int n;
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
bool find(int x)
{
	for(int i=n+1;i<=n<<1;i++) if(line[x][i]&&!used[i])
	{
		used[i]=true; if(!fr[i]||find(fr[i])) {fr[i]=x; return true;}
	}
	return false;
}
void init()
{
	memset(fr,0,sizeof fr); memset(used,false,sizeof used);
	memset(line,false,sizeof line);
}
bool work()
{
	for(int i=1;i<=n;i++)
	{
		memset(used,false,sizeof used);
		if(!find(i)) return false;
	}
	return true;
}
int main()
{
	int cases=rd(); while(cases--)
	{
		init();
		n=rd(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
		{
			a[i][j]=rd(); if(a[i][j]) line[i][j+n]=true;
		}
		printf("%s
",work()?"Yes":"No");
	}
	return 0;
}

小结:二分图真的是好东西啊qwq。

原文地址:https://www.cnblogs.com/ShuraK/p/9801500.html