洛谷P1129 【ZJOI2007】矩阵游戏

原题传送门

题目描述

小QQ是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏。矩阵游戏在一个N \times NN×N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:

行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)

列交换操作:选择矩阵的任意两列,交换这两列(即交换对应格子的颜色)

游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。

对于某些关卡,小QQ百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!于是小QQ决定写一个程序来判断这些关卡是否有解。

输入输出格式

输入格式:

第一行包含一个整数TT,表示数据的组数。

接下来包含TT组数据,每组数据第一行为一个整数NN,表示方阵的大小;接下来NN行为一个N \times NN×N的0101矩阵(00表示白色,11表示黑色)。

输出格式:

包含TT行。对于每一组数据,如果该关卡有解,输出一行YesYes;否则输出一行NoNo。

输入输出样例

输入样例#1: 复制
2
2
0 0
0 1
3
0 0 1
0 1 0
1 0 0
输出样例#1: 复制
No
Yes

说明

对于20\%20%的数据,N ≤ 7N≤7

对于50\%50%的数据,N ≤ 50N≤50

对于100\%100%的数据,N ≤ 200N≤200

题解

前置知识二分图

此题比较有代表性,思维难度较高,建模后代码很简单。

这题的最终目标是要让主对角线上都是黑格,即对于每一个x∈[1,N],满足(x,x)。

于是此时问题就转化为找N个横纵坐标相同的点,于是我们可以这样建模:

我们将行作为左集合,列作为右集合,每个点就是一条边,而交换行就是交换点的顺序

这样一来,我们就很容易发现只要能实现N个匹配,就一定可以通过交换点来达成目标

然后我们就可以运用二分图匹配的模板解决这道题了

 #include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+,MAXN=,MAXM=MAXN*MAXN;
int T,N;
int head[MAXN],to[MAXM],nxt[MAXM],tp;
inline void add(int x,int y){
nxt[++tp]=head[x];
head[x]=tp;
to[tp]=y;
}
int used[MAXN],match[MAXN];
bool dfs(int x){
for(int i=head[x];i;i=nxt[i]){
if(!used[to[i]]){
used[to[i]]=;
if(!match[to[i]]||dfs(match[to[i]])){
match[to[i]]=x;
return ;
}
}
}
return ;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&N);
tp=;
memset(head,,sizeof(head));
memset(match,,sizeof(match));
for(int i=;i<=N;i++){
for(int j=;j<=N;j++){
int ii;
scanf("%d",&ii);
if(ii){
add(i,j);
}
}
}
int flag=;
for(int i=;i<=N&&flag;i++){
memset(used,,sizeof(used));
flag=dfs(i);
}
if(flag){
puts("Yes");
}else{
puts("No");
}
}
return ;
}
上一篇:$loj10156/$洛谷$2016$ 战略游戏 树形$DP$


下一篇:VS2019打开项目加载失败:无法找到 .NET Core SDK。请检查确保已安装此项且 global.json 中指定的版本(如有)与所安装的版本相匹配。