因为题目的最终目的是将对角线全部摆上黑色格子,所以我们在处理数据时只处理黑色就行。
若一个点是黑色的我们可以让此列和此行连一条边。
那么移动之后就成了这条边所连的点变化。
如果排成对角线上全部为黑的话,所有行和列所成的边的顶点没有相交的。
这就是一个二分图的匹配问题。可以用匈牙利算法解决。
若所求的最大匹配>n,则可以排成。
#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
const int maxn=500;
int head[maxn*maxn],to[maxn*maxn],next[maxn*maxn];
int tot=1,ans=0;
int linker[maxn],visit[maxn],n,t;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') w*=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
s=s*10+ch-'0';
ch=getchar();
}
return s;
}
void add(int x,int y)
{
tot++;next[tot]=head[x];head[x]=tot;to[tot]=y;
}
bool dfs(int u)
{
for(int i=head[u];i;i=next[i])
{
int v=to[i];
if(!visit[v])
{
visit[v]=1;
if(!linker[v]||dfs(linker[v]))
{
linker[v]=u;return 1;
}
}
}
return 0;
}
void clear()//防止memset多次重用浪费时间
{
t--;
ans=0;
for(int i=1;i<=tot;i++)
to[i]=head[i]=next[i]=0;
tot=1;
for(int i=1;i<=2*n;i++)
{
linker[i]=0;
}
}
int main()
{
t=read();
while(t)
{
n=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int m1=read();
if(m1==1)
add(i,j+n);
}
for(int i=1;i<=n;i++)
{
memset(visit,0,sizeof(visit));
if(dfs(i))ans++;
}
if(ans>=n)printf("Yes\n");
else printf("No\n");
clear();
}
return 0;
}