• POJ-1422 Air Raid---二分图匹配&最小路径覆盖


    题目链接:

    https://vjudge.net/problem/POJ-1422

    题目大意:

    有n个点和m条有向边,现在要在点上放一些伞兵,然后伞兵沿着图走,直到不能走为止
    每条边只能是一个伞兵走过,问最少放多少个伞兵

    解题思路:

    最小路径覆盖

    最小路径覆盖=|G|-最大匹配数

    重点是,建图的时候,把每个点分成两部分A1,A2,如果有边A->B,就在二分图上加A1->B2

    这里的巧妙可以看下面的例子

    对于一条路径,起点的入度为0,终点的出度为0,中间节点的出入度都为1。

    每一个点最多只能有1个后继,同时每一个点最多只能有1个前驱。

    假如我们选择了一条边(u,v),也就等价于把前驱u和后继v匹配上了。这样前驱u和后继v就不能和其他节点匹配。

    利用这个我们可以这样来构图:

    将每一个点拆分成2个,分别表示它作为前驱节点和后继节点。将所有的前驱节点作为A部,所有后继节点作为B部。

    接下来进行连边,若原图中存在一条边(u,v),则连接A部的u和B部的v。

     

    在这个上面做一个最大二分匹配:

    其中实线表示被选中的匹配,虚线表示未被选中的。

    有没有发现,和原图刚好有着对应的关系。

    这样在匹配结束的时候,我们就可以直接通过匹配的情况来确定选中的路径。

    但是如何保证这样就能得到最小的路径覆盖呢?

    如果一个点是路径起点的话,它在B部的节点一定是没有匹配上的。

    经过最大匹配算法后,B部剩下没有被匹配的点一定是最少的,也就对应了最小需要的路径数。

    所以最小路径覆盖的结果才是N-最大匹配数。

    (上述例子转载自:https://blog.csdn.net/tramp_1/article/details/52742572

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<vector>
     6 #include<queue>
     7 using namespace std;
     8 typedef pair<int, int> Pair ;
     9 typedef long long ll;
    10 const int INF = 0x3f3f3f3f;
    11 const int maxn = 300 + 10;
    12 int T, n, m, cases;
    13 vector<int>G[maxn];
    14 int cx[maxn], cy[maxn];
    15 bool vis[maxn];
    16 bool dfs(int u)
    17 {
    18     for(int i = 0; i < G[u].size(); i++)
    19     {
    20         int v = G[u][i];
    21         if(!vis[v])
    22         {
    23             vis[v]  =1;//加入增广路
    24             if(cy[v] == -1 || dfs(cy[v]))
    25             {
    26                 cx[u] = v;
    27                 cy[v] = u;
    28                 return 1;
    29             }
    30         }
    31     }
    32     return 0;
    33 }
    34 int maxmatch()
    35 {
    36     int ans = 0;
    37     memset(cx, -1, sizeof(cx));
    38     memset(cy, -1, sizeof(cy));
    39     for(int i = 1; i <= n; i++)
    40     {
    41         if(cx[i] == -1)
    42         {
    43             memset(vis, 0, sizeof(vis));
    44             ans += dfs(i);
    45         }
    46     }
    47     return ans;
    48 }
    49 int main()
    50 {
    51     cin >> T;
    52     while(T--)
    53     {
    54         scanf("%d%d", &n, &m);
    55         int x, y;
    56         for(int i = 0; i <= n; i++)G[i].clear();
    57         for(int i = 1; i <= m; i++)
    58         {
    59             scanf("%d%d", &x, &y);
    60             G[x].push_back(y);
    61         }
    62         cout<<(n - maxmatch())<<endl;
    63     }
    64     return 0;
    65 }
  • 相关阅读:
    css文本垂直水平居中
    如何通过eclipse查看、阅读hadoop2.4源码
    hadoop、storm和spark的区别、比较
    Spark学习体系整理(基础篇、中级篇、高级篇所涉及内容)
    scala class和object,trait的区别
    Scala的=>作用
    [Scala函数特性系列]——按名称传递参数
    Python读写文件
    如何向map和reduce脚本传递参数,加载文件和目录
    Java中字符串中子串的查找共有四种方法(indexof())
  • 原文地址:https://www.cnblogs.com/fzl194/p/8835980.html
Copyright © 2020-2023  润新知