原题链接:矩阵游戏
看到题目之后一定要仔细读题并且理解题意。
手动模拟游戏之后发现:
1.如果两个格子在同一列,那么无论如何操作,这两个格子都在同一列。
2.如果两个格子在同一行,那么无论如何操作,这两个格子都在同一行。
3.可以通过操作改变改点在对应行和列中的位置。
那么答案就很明显了,问题有解当且仅当每一行和另一列唯一对应,在行和列的交点上有黑格子。
想到了什么?
可以把行和列分别看成是两个集合里的点,黑格子就是边。现在要求两个集合的唯一映射。
二分图最大匹配!
问题就很简单了,在读入的时候建图,最后再跑一遍匈牙利,如果有完美匹配(最大匹配==行数),那么就有解。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int read(){
char ch=getchar();int num=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
return num;
}
int n,k[209];
bool g[209][209],used[209];
bool fid(int x);
void work();
int main()
{
int Case=read();
while(Case--){
work();
}
return 0;
}
void work(){
int num=0;
n=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=read();
memset(k,0,sizeof(k));
for(int i=1;i<=n;i++){
memset(used,0,sizeof(used));
if(fid(i))num++;
else break;
}
if(num==n){printf("Yes\n");return;}
else {printf("No\n");return;}
}
bool fid(int x){
for(int j=1;j<=n;j++){
if(g[x][j]&&!used[j]){
used[j]=1;
if(k[j]==0||fid(k[j])){
k[j]=x;
return true;
}
}
}
return false;
}
/*
* 模一模很容易得到规律
* 要找到每一行对应一个黑格子,并且每一列也对应唯一一个黑格子
* 每找到一个黑格子,就在对应的行和列连线
* 如果行和列的最大匹配为n,那么就可以配对
*/