题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1059
思路
实际上在这个游戏中,我们可以随心所欲地将任意一个格子移动到指定的位置上去,进一步的研究还可以发现,每一行只能有一个格子被移动,每一列也只能有一个格子被移动。那么要想达到最终这个n*n的棋盘的对角线上都是黑格子,就需要有n个黑格子(xi,yi),而且任意的xi均不相同,任意的yi均不相同。那么我们可以想到二分图建模,将行号当成x侧的点,将列号当成y侧的点,对于任意的黑格子(xi,yi),xi向yi连一条边,对这个建好的二分图跑最大匹配,最后检查所有的x点(y点)是否都被匹配上了,若都被匹配上了,则此游戏有解,否则此游戏无解。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXE 61000
#define MAXV 1000
using namespace std;
int n;
struct edge
{
int u,v,next;
}edges[MAXE];
int head[MAXV],nCount=0;
void AddEdge(int U,int V)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].next=head[U];
head[U]=nCount;
}
int vis_cnt=0,pre[MAXV],vis[MAXV];
bool find(int u)
{
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(vis[v]==vis_cnt) continue;
vis[v]=vis_cnt;
if(pre[v]==-1||find(pre[v]))
{
pre[v]=u;
return true;
}
}
return false;
}
void work()
{
memset(pre,-1,sizeof(pre));
for(int i=1;i<=n;i++)
{
vis_cnt++;
find(i);
}
for(int i=1;i<=n;i++)
if(pre[i]==-1)
{
puts("No");
return;
}
puts("Yes");
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
nCount=0;
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int x;
scanf("%d",&x);
if(x) AddEdge(i,j);
}
work();
}
return 0;
}