hoj 2739 中國郵局問題

  1 /*若原圖的基圖不連通,
  2 或者存在某個點的入度或出度爲 0 則無解。
  3 統計全部點的入度出度之差 Di, 對於 Di > 0 的點,
  4 加邊(s, i, Di, 0); 對於 Di < 0 的點加邊(i, t, -Di,0);
  5 對原圖中的每條邊(i, j),
  6 在網絡中加邊(i, j, ∞, Dij),Dij 爲邊(i, j)的權值。
  7 求一次最小費用流,費用加上原圖全部邊權和即爲結果。
  8 若進一步要求輸出最小權值迴路,則對全部流量 fij > 0 的邊(i, j),在原圖中複製fij 份,這樣原圖便成爲歐拉圖,求一次歐拉回路便可。
  9 */
 10 #include <iostream>
 11 #include <cstdio>
 12 #include <cstring>
 13 #include <queue>
 14 #include <algorithm>
 15 #include <cmath>
 16 
 17 using namespace std;
 18 
 19 const int maxn = 1e2 + 5;
 20 const int maxm = 2e4 + 5;
 21 const int inf = 0x3f3f3f3f;
 22 
 23 struct MCMF {
 24     struct Edge {
 25         int v, c, w, next;
 26     }p[maxm << 1];
 27     int e, head[maxn], dis[maxn], pre[maxn], cnt[maxn], sumFlow, n;
 28     bool vis[maxn];
 29     void init(int nt){
 30         e = 0, n = nt + 1;
 31         memset(head, -1, sizeof(head[0]) * (n + 2));
 32     }
 33     void addEdge(int u, int v, int c, int w){
 34         p[e].v = v; p[e].c = c; p[e].w = w; p[e].next = head[u]; head[u] = e++;
 35         swap(u, v);
 36         p[e].v = v; p[e].c = 0; p[e].w = -w; p[e].next = head[u]; head[u] = e++;
 37     }
 38     bool spfa(int S, int T){
 39         queue <int> q;
 40         for (int i = 0; i <= n; ++i)
 41             vis[i] = cnt[i] = 0, pre[i] = -1, dis[i] = inf;
 42         vis[S] = 1; dis[S] = 0;
 43         q.push(S);
 44         while (!q.empty()){
 45             int u = q.front(); q.pop();
 46             vis[u] = 0;
 47             for (int i = head[u]; i + 1; i = p[i].next){
 48                 int v = p[i].v;
 49                 if (p[i].c && dis[v] > dis[u] + p[i].w){
 50                     dis[v] = dis[u] + p[i].w;
 51                     pre[v] = i;
 52                     if (!vis[v]){
 53                         q.push(v);
 54                         vis[v] = 1;
 55                         if (++cnt[v] > n) return 0;
 56                     }
 57                 }
 58             }
 59         }
 60         return dis[T] != inf;
 61     }
 62     int mcmf(int S, int T){
 63         sumFlow = 0;
 64         int minFlow = 0, minCost = 0;
 65         while (spfa(S, T)){
 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                 p[i].c -= minFlow;
 72                 p[i ^ 1].c += minFlow;
 73             }
 74             minCost += dis[T] * minFlow;
 75         }
 76         return minCost;
 77     }
 78     int ind[maxn], outd[maxn], ans ;
 79     bool build(int nt, int mt){
 80         init(nt);
 81         memset(ind, 0, sizeof(ind));
 82         memset(outd, 0, sizeof(outd));
 83         ans = 0;
 84         int u, v, c;
 85         while (mt--){
 86             scanf("%d%d%d", &u, &v, &c);
 87             u++, v++;
 88             addEdge(u, v, inf, c);
 89             ans += c;
 90             outd[u]++, ind[v]++;
 91         }
 92         for (int i = 1; i <= nt; ++i){
 93             if (ind[i] == 0 || outd[i] == 0) return false;
 94         }
 95         for (int i = 1; i <= nt; ++i){
 96             if (ind[i] - outd[i] > 0)
 97                 addEdge(0, i, ind[i] - outd[i], 0);
 98             else if (ind[i] - outd[i] < 0) 
 99                 addEdge(i, n, outd[i] - ind[i], 0);
100         }
101         return true;
102     }
103     void solve(){
104         ans += mcmf(0, n);
105         printf("%d\n", ans);
106     }
107 }my;
108 int main(){
109     int tcase, n, m;
110     scanf("%d", &tcase);
111     while (tcase--){
112         scanf("%d%d", &n, &m);
113         if (!my.build(n, m)){
114             printf("-1\n");
115             continue;
116         }
117         my.solve();
118     }
119     return 0;
120 }
相關文章
相關標籤/搜索