• [HIHO1394]最小路径覆盖(二分匹配,最小路径覆盖)


    题目链接:http://hihocoder.com/problemset/problem/1394

    相当于数一数最少有多少条链,这就是最小路径覆盖问题:给定一个有向无环图,用最少的路径数量去保证所有点都被覆盖住。

    利用有向图中一条链的前驱和后继唯一(也可能没有)这一条性质就可以建立二分图,最大匹配出的结果就相当于确定了前驱和后继的关系。

    记住这个模型!

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 5050;
     5 const int inf = 0x3f3f3f3f;
     6 int nx,ny;
     7 int G[maxn][maxn];
     8 int linker[maxn],lx[maxn],ly[maxn];
     9 int slack[maxn];
    10 bool visx[maxn],visy[maxn];
    11 
    12 bool dfs(int x) {
    13     visx[x] = true;
    14     for(int y = 0; y < ny; y++) {
    15         if(visy[y])continue;
    16         int tmp = lx[x] + ly[y] - G[x][y];
    17         if(tmp == 0) {
    18             visy[y] = true;
    19             if(linker[y] == -1 || dfs(linker[y])) {
    20                 linker[y] = x;
    21                 return true;
    22             }
    23         }
    24         else if(slack[y] > tmp)
    25             slack[y] = tmp;
    26     }
    27     return false;
    28 }
    29 int km() {
    30     memset(linker,-1,sizeof(linker));
    31     memset(ly,0,sizeof(ly));
    32     for(int i = 0;i < nx;i++) {
    33         lx[i] = -inf;
    34         for(int j = 0;j < ny;j++)
    35             if(G[i][j] > lx[i])
    36                 lx[i] = G[i][j];
    37     }
    38     for(int x = 0;x < nx;x++) {
    39         for(int i = 0;i < ny;i++)
    40             slack[i] = inf;
    41         while(true) {
    42             memset(visx,false,sizeof(visx));
    43             memset(visy,false,sizeof(visy));
    44             if(dfs(x))break;
    45             int d = inf;
    46             for(int i = 0;i < ny;i++)
    47                 if(!visy[i] && d > slack[i])
    48                     d = slack[i];
    49             for(int i = 0;i < nx;i++)
    50                 if(visx[i])
    51                     lx[i] -= d;
    52             for(int i = 0;i < ny;i++) {
    53                 if(visy[i])ly[i] += d;
    54                 else slack[i] -= d;
    55             }
    56         }
    57     }
    58     int res = 0;
    59     for(int i = 0;i < ny;i++)
    60         if(linker[i] != -1)
    61             res += G[linker[i]][i];
    62     return res;
    63 }
    64 
    65 int n, m;
    66 
    67 int main() {
    68     // freopen("in", "r", stdin);
    69     int u, v;
    70     while(~scanf("%d%d",&n,&m)) {
    71         nx = ny = n;
    72         memset(G, 0, sizeof(G));
    73         for(int i = 0; i < m; i++) {
    74             scanf("%d%d",&u,&v);
    75             G[u-1][v-1] = 1;
    76         }
    77         printf("%d
    ", nx-km());
    78     }
    79     return 0;
    80 }
  • 相关阅读:
    Java数据处理,Map中数据转double并取小数点后两位
    19年7月份面试7家公司,整理的java面试题(答案自行百度解决,也是个学习的过程)
    2019阿里云面试题,竟然现场敲代码,现在的企业越来越实在了
    解决win10状态栏的搜索框无法搜索本地应用或无反应
    sql,按照时间排序,取前N条
    List数组排序
    阿里云的maven仓库 地址
    hashcode相等两个类一定相等吗?equals呢?相反呢?
    杂记
    java排序
  • 原文地址:https://www.cnblogs.com/kirai/p/6789078.html
Copyright © 2020-2023  润新知