• 洛谷P1129 【ZJOI2007】矩阵游戏


    原题传送门

    题目描述

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

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

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

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

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

    输入输出格式

    输入格式:

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

    接下来包含TT组数据,每组数据第一行为一个整数NN,表示方阵的大小;接下来NN行为一个N imes 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 ≤ 7N7

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

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

    题解

    前置知识二分图

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

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

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

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

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

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

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int INF=1e9+7,MAXN=201,MAXM=MAXN*MAXN;
     5 int T,N;
     6 int head[MAXN],to[MAXM],nxt[MAXM],tp;
     7 inline void add(int x,int y){
     8     nxt[++tp]=head[x];
     9     head[x]=tp;
    10     to[tp]=y;
    11 }
    12 int used[MAXN],match[MAXN];
    13 bool dfs(int x){
    14     for(int i=head[x];i;i=nxt[i]){
    15         if(!used[to[i]]){
    16             used[to[i]]=1;
    17             if(!match[to[i]]||dfs(match[to[i]])){
    18                 match[to[i]]=x;
    19                 return 1;
    20             }
    21         }
    22     }
    23     return 0;
    24 }
    25 int main(){
    26     scanf("%d",&T);
    27     while(T--){
    28         scanf("%d",&N);
    29         tp=0;
    30         memset(head,0,sizeof(head));
    31         memset(match,0,sizeof(match));
    32         for(int i=1;i<=N;i++){
    33             for(int j=1;j<=N;j++){
    34                 int ii;
    35                 scanf("%d",&ii);
    36                 if(ii){
    37                     add(i,j);
    38                 }
    39             }
    40         }
    41         int flag=1;
    42         for(int i=1;i<=N&&flag;i++){
    43             memset(used,0,sizeof(used));
    44             flag=dfs(i);
    45         }
    46         if(flag){
    47             puts("Yes");
    48         }else{
    49             puts("No");
    50         }
    51     }
    52     return 0;
    53 }
  • 相关阅读:
    MySQL进阶:主主复制+Keepalived高可用
    Zabbix 5.0:磁盘自动发现和读写监控
    Zabbix 5.0 优化建议
    容器进阶:OCI与容器运行时
    openresty快速安装
    ansible:playbook详解
    Shell:如何遍历包含空格的文本
    Linux性能优化:内存使用情况分析
    Shell:如何写一个多选菜单的脚本
    算法路漫漫(二) 递归与归并
  • 原文地址:https://www.cnblogs.com/guoshaoyang/p/10567021.html
Copyright © 2020-2023  润新知