这道题和横行和竖列交换的操作看起来与二分图无关
在看了题解的思想后才知道,可以将每个黑子的横坐标与纵坐标之间连边,然后跑最大匹配,如果最大匹配n,则yes
为什么呢?其实对于交换行和列,可以理解为改变左右两部的节点编号,去满足i->i之间有边,而我们不想进行改编号的操作,那么就可以去算最大匹配,如果最大匹配大于等于n,那就意味着可以通过改变编号的方式达到对角线的位置上有棋子
这道题的思路真的很不错
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=160005;
int t,n,x,cnt,mat[maxn],vis[maxn],head[maxn];
struct edge
{
int to,nxt;
}G[maxn];
void add(int x,int y)
{
G[++cnt].to=y; G[cnt].nxt=head[x]; head[x]=cnt;
}
bool dfs(int u)
{
for(int i=head[u];i;i=G[i].nxt)
{
int to=G[i].to;
if(!vis[to])
{
vis[to]=1;
if(!mat[to] || dfs(mat[to]))
{
mat[to]=u;
return true;
}
}
}
return false;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(head,0,sizeof(head));
cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&x);
if(x==1) add(i,j);
}
memset(mat,0,sizeof(mat));
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)) ans++;
}
if(ans>=n) printf("Yes\n");
else printf("No\n");
}
return 0;
}
这个数组一定要开够大啊,边数一定要n^2