hdu 1853 (费用流 拆点)

// 给定一个有向图,必须用若干个环来覆盖整个图,要求这些覆盖的环的权值最小。 

思路:原图每个点 u 拆为 u 和 u' ,从源点引容量为 1 费用为 0 的边到 u ,从 u' 引相同性质的边到汇点,若原图中存在 (u, v) ,则从 u 引容量为 1 费用为 c(u, v) 的边到 v' 。

其实这里的源模拟的是出度,汇模拟的是入度,因为环中每个点的出度等于入度等于 1 ,那么如果最大流不等于顶点数 n ,则无解;否则,答案就是最小费用。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <queue>
  5 
  6 using namespace std;
  7 
  8 const int maxn = 2e2 + 5;
  9 const int maxm = 2e4 + 5;
 10 const int inf = 0x3f3f3f3f;
 11 
 12 struct MCMF
 13 {
 14     struct Edge
 15     {
 16         int v, c, w, next;
 17     }p[maxm << 1];
 18     int e, head[maxn], dis[maxn], pre[maxn], cnt[maxn], sumFlow, n;
 19     bool vis[maxn];
 20     void init(int nt)
 21     {
 22         e = 0, n = nt;
 23         memset(head, -1, sizeof(head[0]) * (n + 2) );
 24     }
 25     void addEdge(int u, int v, int c, int w)
 26     {
 27         p[e].v = v, p[e].c = c; p[e].w = w; p[e].next = head[u]; head[u] = e++;
 28         swap(u, v);
 29         p[e].v = v, p[e].c = 0; p[e].w = -w; p[e].next = head[u]; head[u] = e++;
 30     }
 31     bool spfa(int S, int T)
 32     {
 33         queue <int> q;
 34         for (int i = 0; i <= n; ++i)
 35             vis[i] = cnt[i] = 0, pre[i] = -1, dis[i] = inf;
 36         vis[S] = 1, dis[S] = 0;
 37         q.push(S);
 38         while (!q.empty())
 39         {
 40             int u = q.front(); q.pop();
 41             vis[u] = 0;
 42             for (int i = head[u]; i + 1; i = p[i].next)
 43             {
 44                 int v = p[i].v;
 45                 if (p[i].c && dis[v] > dis[u] + p[i].w)
 46                 {
 47                     dis[v] = dis[u] + p[i].w;
 48                     pre[v] = i;
 49                     if (!vis[v])
 50                     {
 51                         q.push(v);
 52                         vis[v] = 1;
 53                         if (++cnt[v] > n) return 0;
 54                     }
 55                 }
 56             }
 57         }
 58         return dis[T] != inf;
 59     }
 60     int mcmf(int S, int T)
 61     {
 62         sumFlow = 0;
 63         int minFlow = 0, minCost = 0;
 64         while (spfa(S, T))
 65         {
 66             minFlow = inf + 1;
 67             for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ])
 68                 minFlow = min(minFlow, p[i].c);
 69             sumFlow += minFlow;
 70             for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ])
 71             {
 72                 p[i].c -= minFlow;
 73                 p[i ^ 1].c += minFlow;
 74             }
 75             minCost += dis[T] * minFlow;
 76         }
 77         return minCost;
 78     }
 79     void build(int nt, int mt)
 80     {
 81         init((nt << 1) + 1);
 82         int u, v, c;
 83         for (int i = 1; i <= nt; ++i)
 84         {
 85             addEdge(0, i, 1, 0);
 86             addEdge(i + nt, n, 1, 0);
 87         }
 88         while (mt--)
 89         {
 90             scanf("%d%d%d", &u, &v, &c);
 91             addEdge(u, v + nt, 1, c);
 92         }
 93     }
 94     void solve(int nt)
 95     {
 96         int ans = mcmf(0, n);
 97         if ( sumFlow != nt)
 98             printf("-1
");
 99         else
100             printf("%d
", ans);
101     }
102 }my;
103 
104 int main()
105 {
106     int n, m;
107     while (~scanf("%d%d", &n, &m))
108     {
109         my.build(n, m);
110         my.solve(n);
111     }
112     return 0;
113 }
原文地址:https://www.cnblogs.com/Missa/p/3265691.html