zoukankan      html  css  js  c++  java
  • 0x68

    链接:https://ac.nowcoder.com/acm/contest/1062/C

    题目描述

    给定一个N行M列的棋盘,已知某些格子禁止放置。

    问棋盘上最多能放多少个不能互相攻击的車。

    車放在格子里,攻击范围与中国象棋的“車”一致。

    输入描述:

    第一行包含三个整数N,M,T,其中T表示禁止放置的格子的数量。
    接下来T行每行包含两个整数x和y,表示位于第x行第y列的格子禁止放置,行列数从1开始。
    

    输出描述:

    输出一个整数,表示结果。
    

    示例1

    输入

    8 8 0
    

    输出

    8
    

    思路

    先分析出之前讲的 (0/1要素)

    “1要素”
    每行、每列只能放1个车(不然就能互相攻击到)。某个格子 ((i,j)) 如果放了车,就等于占用了第 (i) 行与第 (j) 列放車的“名额”
    因此,我们可以把行、列看作节点,一共(N+M)个节点。如果格子((i,j)) 没有被禁止,就在第 (i)行对应的节点与第 (j) 行对应的节点之间连无向边。

    “0要素”:

    每个車显然不能既在第 (i_1) 行又在第 $ i_2$ 行,所以两个“行”对应的节点之间没有边。对于“列”也同理。
    因此,刚才构建的无向图是二分图,我们可以把N个“行节点”作为左部,M个列节点”作为右部。
    更在不能互相攻击的前提下放置的车最多,就是求上述分图的最大匹配,时间复杂度为 (O((N +M)*NM))

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    int n, m, t, f[210], b[210], ans;
    bool a[210][210], v[210];
    
    bool dfs(int x) {
        for (int i = 1; i <= m; ++i) {
            if (v[i] || a[x][i])continue;
            v[i] = 1;
            if (f[i] == 0 || dfs(f[i])) {
                f[i] = x; return true;
            }
        }
        return false;
    }
    
    int main() {
        //freopen("in.txt", "r", stdin);
        ios::sync_with_stdio(false), cin.tie(0);
        cin >> n >> m >> t;
        for (int j = 1; j <= t; ++j) {
            int x, y; cin >> x >> y;
            a[x][y] = 1;
        }
        for (int i = 1; i <= n; ++i) {
            memset(v, 0, sizeof v);
            if (dfs(i))++ans;
        }
        cout << ans << endl;
    }
    

    一些匹配方法:

    完备匹配:

    给定一张二分图,其左部、右部点数相同,均为 (N) 个节点。如果该二分图的最大匹配包含 (N)

    条匹配边,则称该二分图具有完备匹配

    多重匹配:

    给定一张包含 (N) 个左部节点、(M) 个右部节点的二分图。从中选出尽量多的边,使第 (i (1 <= i <=N)) 个左部节点至多与 (kl_i) 条选出的边相连,第 (j(i <= j <= M)) 个右部节点至多与 (kr_j) 条选出的边相连。该问题被称为二分图的多重匹配。

    (kl_i=kr_j=1) 时,上述问题就简化为二分图最大匹配。因此,多重匹配是一个广义的“匹配”问题,每个节点可以与不止一条“匹配”边相连,但不能超过一.个给定的限制。
    多重匹配一般有 四种解决方案:

    1.拆点。把第 $i $个左部节点拆成 (kl_i)个不同的左部节点,第j个右部节点拆成 (kr_j)个右部节点。对于原

    图中的每条边 ((i,j)), 在i拆成的所有节点与 (j) 拆成的所有节点之间连边。然后求解二分图最大匹配。

    2.如果所有的 (kl_i= 1),或者所有的 (kr_j= 1),即只有一侧是“多重”匹配,不妨设左部是“多重”的,那么可以

    直接在匈牙利算法中让每个左部节点执行 $kl_i $ 次dfs​。

    3.在第2种方案中,当然也可以交换左右两部,设“右部”是多重的,修改匈牙利算法的实现,让右部

    节点可以匹配 (kr_j)次,超过匹配次数后,就要依次尝试递归当前匹配的 (kr_j)个左部节点,看能否找到增广路

    4.网络流。这是最一般也是最高效的解决方法。但博主尚未学习(可能以后会补上)。

  • 相关阅读:
    【mongoDB运维篇④】Shard 分片集群
    【Linux高频命令专题(11)】cp
    【Linux高频命令专题(10)】mv
    Nginx + Lua + 共享内存
    ngx_lua模块学习示例之waf
    在 Golang 中使用 Protobuf
    openresty package.path require 报错
    ngx_lua 模块
    Lua中的常用语句结构以及函数
    lua日期与时间操作
  • 原文地址:https://www.cnblogs.com/RioTian/p/13476793.html
Copyright © 2011-2022 走看看