// 給定一個有向圖,必須用若干個環來覆蓋整個圖,要求這些覆蓋的環的權值最小。 ios
思路:原圖每一個點 u 拆爲 u 和 u' ,從源點引容量爲 1 費用爲 0 的邊到 u ,從 u' 引相同性質的邊到匯點,若原圖中存在 (u, v) ,則從 u 引容量爲 1 費用爲 c(u, v) 的邊到 v' 。ui
其實這裏的源模擬的是出度,匯模擬的是入度,由於環中每一個點的出度等於入度等於 1 ,那麼若是最大流不等於頂點數 n ,則無解;不然,答案就是最小費用。spa
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\n"); 99 else 100 printf("%d\n", 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 }