• [ZJOI2007]矩阵游戏


    这道题是一个不错的题,难点就在于建模。

    交换操作过程中,同一行的黑块是不会被拆开,同理纵块也是。

    接着目标状态就是一条对角线上全都是黑块。

    我们倒过来想,看看能否从目标状态变成初始状态。

    对于所有的黑块$(x,y)$(左边行右边列,点分行列),我们连条边$x leftarrow ightarrow y$。

    显然目标状态应该是完全匹配的。

    交换两行$i$、$j$,所有在行$i$、$j$的黑块的横坐标交换,纵坐标不变就是将所有指向行$i$的点的指向改成行$j$,所有指向行$j$的点改指向行$i$。

    同理纵坐标也是。

    等效替代下发现实质上与交换点$i$和点$j$的效果一样。

    也就是从目标状态无论怎样变换匹配数不变且满。

    且以上操作可逆。

    所以我们检查下原图是否能全部匹配即可。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int maxn = 200 + 5;
     6 
     7 int vis[maxn], lk[maxn], e[maxn][maxn];
     8 int n, T;
     9 
    10 bool find(int u, int tag) {
    11     for (register int v = 1; v <= n; ++v)
    12         if (e[u][v] && vis[v] != tag) {
    13             vis[v] = tag;
    14             if (!lk[v] || find(lk[v], tag)) {
    15                 lk[v] = u;
    16                 return true;
    17             }
    18         }
    19     return false;
    20 }
    21 
    22 int main() {
    23     scanf("%d", &T);
    24     for (register int kase = 1; kase <= T; ++kase) {
    25         scanf("%d", &n);
    26         for (register int i = 1; i <= n; ++i)
    27             for (register int j = 1; j <= n; ++j) {
    28                 int x;
    29                 scanf("%d", &x);
    30                 e[i][j] = x;
    31             }
    32         memset(vis, 0, sizeof(vis));
    33         memset(lk, 0, sizeof(lk));
    34         register int cnt = 0;
    35         for (register int i = 1; i <= n; i++)
    36             if (find(i, i)) cnt++;
    37         if (cnt == n) printf("Yes
    ");
    38         else printf("No
    ");
    39     }
    40     return 0;
    41 }
  • 相关阅读:
    入门系列4
    入门系列3
    入门系列2
    入门系列1
    sql进阶-筛选库表中数据为空的表
    sql进阶-删除所有的视图
    sql序列(2) sql语句功能表
    sql序列(5)事务
    sql序列(4)存储过程
    KVM虚拟化介绍
  • 原文地址:https://www.cnblogs.com/ac-evil/p/10350953.html
Copyright © 2020-2023  润新知