[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 }
原文地址:https://www.cnblogs.com/kirai/p/6789078.html