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

https://www.luogu.com.cn/problem/P1129
n*n个格子的矩阵有黑白两色,问是否能经过有限次行交换和列交换使得主多角线上都是黑色(用1表示)。
主对角线上全是黑色,我们可以反着推,对于一个单位矩阵,任意次行交换列交换之后矩阵总是满足一个一个性质,每一行只与唯一的列交点为1,就是不存在任意两个点1的行数相等,也不存在列数相等。行交换列交换都是可逆的,所以如果矩阵满足这样的性质就一定可以交换得到主对角线都是1,找这样的性质首先想到了八皇后,用dfs去遍历,可是n的范围是200啊一定会超时的。最后看了题解,只能拍手称妙啊,佩服的五体投地。不是每一行都要存在有一个唯一的列为1,那不就相当于可以想象在行和列之间建条边,行和列分别是二分图两部分中的点,如果存在最大匹配等n就是可以满足那个性质,或者说是每个行都可以找到一个列与他匹配。接下来就是套板子了

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N=210;
int n,m,a[N][N];
bool st[N]; 
int p[N],h[N],e[N*N],ne[N*N],idx;
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
 } 
bool find(int x)
{
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int y=e[i];
		if(!st[y])
		{
			st[y]=1;
			if(!p[y]||find(p[y]))
			{
				p[y]=x;//保存每一列是否匹配过以及和谁匹配
				return 1;
			}
		}
	}
	return 0;
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		memset(h,-1,sizeof h);
		cin>>n;
		idx=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				cin>>a[i][j];
				if(a[i][j])
					add(i,j);//只需要一条i到j的边就可以了
			}
		bool flag=1;
		memset(p,0,sizeof p);
		for(int i=1;i<=n;i++)
		{
			memset(st,0,sizeof st);//清空标记,给i匹配过程中都找过那些点
			if(!find(i)) 
			{
				flag=0;
				break;
			} 
		}
		if(flag) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/neflibata/p/12871772.html