Hdu 3488 Tour (KM 有向环覆盖)

题目链接:

  Hdu 3488 Tour

题目描述:

  有n个节点,m条有权单向路,要求用一个或者多个环覆盖所有的节点。每个节点只能出现在一个环中,每个环中至少有两个节点。问最小边权花费为多少?

解题思路:

  因为每个节点就出现一个,那么每个节点出度和入度都为1咯。我们可以对每个节点u拆点为u,u',分别放在集合X,Y.然后对两个集合进行完备匹配。完备匹配成功以后,每个节点就会有只有一个出度,一个入度的。

用KM求最小匹配的话,先初始化maps为-INF,然后把各边权值存为负,求出最大值取反即可。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 const int maxn = 310;
 7 const int INF = 0x3f3f3f3f;
 8 int maps[maxn][maxn], used[maxn], s[maxn], n;
 9 int lx[maxn], ly[maxn];
10 bool visx[maxn], visy[maxn];
11 bool Find (int x)
12 {
13     visx[x] = 1;
14     for (int i=1; i<=n; i++)
15     {
16         if (!visy[i] && lx[x]+ly[i]==maps[x][i])
17         {
18             visy[i] = 1;
19             if (!used[i] || Find(used[i]))
20             {
21                 used[i] = x;
22                 return true;
23             }
24         }
25         else
26             s[i] = min (s[i], lx[x] + ly[i] - maps[x][i]);
27     }
28     return false;
29 }
30 int KM ()
31 {
32     memset (used, 0, sizeof(used));
33     memset (lx, 0, sizeof(lx));
34     memset (ly, 0, sizeof(ly));
35     for (int i=1; i<=n; i++)
36         for (int j=1; j<=n; j++)
37             lx[i] = max (lx[i], maps[i][j]);
38     for (int i=1; i<=n; i++)
39     {
40         for (int j=1; j<=n; j++)
41             s[j] = INF;
42         while (1)
43         {
44             memset (visx, 0, sizeof(visx));
45             memset (visy, 0, sizeof(visy));
46             if (Find(i))
47                 break;
48             int d = INF;
49             for (int j=1; j<=n; j++)
50                 if (!visy[j])
51                     d = min (s[j], d);
52             for (int j=1; j<=n; j++)
53             {
54                 if (visx[j])
55                     lx[j] -= d;
56                 if (visy[j])
57                     ly[j] += d;
58             }
59         }
60     }
61     int res = 0;
62     for (int i=1; i<=n; i++)
63         res += maps[used[i]][i];
64     return res;
65 }
66 int main ()
67 {
68     int m, t;
69     scanf ("%d", &t);
70     while (t --)
71     {
72         scanf("%d %d", &n, &m);
73         for (int i=1; i<=n; i++)
74             for (int j=1; j<=n; j++)
75                 maps[i][j] = -INF;
76         while (m --)
77         {
78             int u, v, s;
79             scanf ("%d %d %d", &u, &v, &s);
80             maps[u][v] = max(maps[u][v], -s;
81         }
82         printf ("%d
", -KM());
83     }
84     return 0;
85 }
本文为博主原创文章,未经博主允许不得转载。
原文地址:https://www.cnblogs.com/alihenaixiao/p/4702762.html