source: http://acm.hdu.edu.cn/showproblem.php?pid=4067
分析转载自: http://blog.csdn.net/fp_hzq/article/details/6852778#reply
#include <stdio.h> #include <cmath> #include <algorithm> using namespace std; const int N = 105; //点数 const int M = (2000+N)<<1; //边数 const int inf = 0X7FFFFFFF; struct e{ int v, nxt; int flow; int cost; }es[M]; int fir[N], dist[N], que[N+10], vis[N], par[N], path[N]; int n, en; int m, s, t; int in[N], ans, sum; void add_e(int u, int v, int flow, int cost){ es[en].v = v; es[en].flow = flow; es[en].cost = cost; es[en].nxt = fir[u]; fir[u] = en++; } void insert(int u, int v, int flow, int cost){ add_e(u, v, flow, cost); add_e(v, u, 0, -cost); } bool spfa(int n, int s, int t){ int l, r, i, v, u, cur, cnt; for(i = 0; i < n; i++) dist[i] = inf, vis[i] = 1; l = r = 0; que[r++] = s; dist[s] = 0; vis[s] = 0; cnt = n+1; while(l != r){ for(v = que[l], l = (l+1)%cnt, cur = fir[v], vis[v] = 1; cur != -1; cur = es[cur].nxt){ if(es[cur].flow > 0 && es[cur].cost+dist[v] < dist[u = es[cur].v]){ dist[u] = es[cur].cost+dist[v]; par[u] = v; path[u] = cur; //path[u]表示的是通过path[u]这条边访问到u这个点的 if(vis[u]){ vis[u] = 0; if(l != r && dist[u] < dist[que[l]]){ //插入到队首 l = (l == 0 ? cnt-1 : l-1); que[l] = u; }else{ //插入到队尾 que[r] = u; r = (r+1)%cnt; } } } } } return dist[t] != inf; } int minflow(int n, int s, int t){ //n表示的是节点数,s为源点,t为汇点 int Min, v, flow = 0; while(spfa(n, s, t)){ Min = inf; v = t; while(v != s){ Min = min(Min, es[path[v]].flow); v = par[v]; } sum -= Min; v = t; while(v != s){ flow += Min*es[path[v]].cost; es[path[v]].flow -= Min; es[path[v]^1].flow += Min; v = par[v]; } } return flow; } template <typename T> void getNum(T& a){ a = 0; char ch; while(true){ ch = getchar(); if(ch >= '0' && ch <= '9') break; } a = ch - '0'; while(true){ ch = getchar(); if(ch < '0' || ch > '9') break; a = a * 10 + ch - '0'; } } bool input(){ getNum(n); getNum(m); getNum(s); getNum(t); int i, u, v, a, b; for(i = 0; i <= n+1; i++){ fir[i] = -1; in[i] = 0; } en = ans = sum = 0; for(i = 1; i <= m; i++){ getNum(u); getNum(v); getNum(a); getNum(b); if(a <= b){ insert(v, u, 1, b - a); in[v]++; in[u]--; ans += a; }else{ insert(u, v, 1, a - b); ans += b; } } in[s]++; in[t]--; for(i = 1; i <= n; i++){ if(in[i] > 0){ insert(0, i, in[i], 0); sum += in[i]; }else if(in[i] < 0){ insert(i, n+1, -in[i], 0); } } s = 0; t = n+1; return true; } int cnt = 0; void solve(){ ans += minflow(n+2, s, t); if(sum == 0){ printf("Case %d: %d\n", ++cnt, ans); }else{ printf("Case %d: impossible\n", ++cnt); } } int main(){ int t; getNum(t); while(t--){ input(); solve(); } return 0; }