hoj 2543 (费用流 拆边)
http://acm.hit.edu.cn/hoj/problem/view?id=2543
1.将原图中的每条边(u, v)拆成两条:(u, v, Ci, 0), (u, v, ∞, Ei)
2.购买的每个石头的费用P加一条 (S, 1, inf, P)的边。
3.总的能够花费的费用C可以在我们求最小费用路的时候判断。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 #include <cmath> 7 8 using namespace std; 9 typedef long long LL; 10 const int maxn = 1e3 + 5; 11 const int maxm = 1e5+ 5; 12 const int inf = 0x3f3f3f3f; 13 14 struct MCMF 15 { 16 struct Edge 17 { 18 int v, c, w, next; 19 }p[maxm << 1]; 20 int e, head[maxn], dis[maxn], pre[maxn], cnt[maxn], sumFlow, n; 21 bool vis[maxn]; 22 void init(int nt) 23 { 24 e = 0, n = nt; 25 memset(head, -1, sizeof(head[0]) * (n + 2) ); 26 } 27 void addEdge(int u, int v, int c, int w) 28 { 29 p[e].v = v; p[e].c = c; p[e].w = w; p[e].next = head[u]; head[u] = e++; 30 swap(u, v); 31 p[e].v = v; p[e].c = 0; p[e].w = -w; p[e].next = head[u]; head[u] = e++; 32 } 33 bool spfa(int S, int T) 34 { 35 queue <int> q; 36 for (int i = 0; i <= n; ++i) 37 vis[i] = cnt[i] = 0, pre[i] = -1, dis[i] = inf; 38 vis[S] = 1, dis[S] = 0; 39 q.push(S); 40 while (!q.empty()) 41 { 42 int u = q.front(); q.pop(); 43 vis[u] = 0; 44 for (int i = head[u]; i + 1; i = p[i].next) 45 { 46 int v = p[i].v; 47 if (p[i].c && dis[v] > dis[u] + p[i]. w) 48 { 49 dis[v] = dis[u] + p[i].w; 50 pre[v] = i; 51 if (!vis[v]) 52 { 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 void mcmf(int S, int T, int ct) 63 { 64 sumFlow = 0; 65 LL minFlow = 0, minCost = 0; 66 while (spfa(S, T)) 67 { 68 minFlow = inf + 1; 69 for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ]) 70 minFlow = min(minFlow,(LL)p[i].c); 71 sumFlow += minFlow; 72 for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ]) 73 { 74 p[i].c -= minFlow; 75 p[i ^ 1].c == minFlow; 76 } 77 minCost += dis[T] * minFlow; 78 if (minCost > ct) 79 { 80 sumFlow -= ceil((minCost - ct) * 1.0 / dis[T]); 81 break; 82 } 83 } 84 } 85 void build(int nt, int mt, int ct, int pt) 86 { 87 init(nt); 88 int u, v, c, w; 89 addEdge(0, 1, inf, pt); 90 while (mt--) 91 { 92 scanf("%d%d%d%d", &u, &v, &c, &w); 93 u++, v++; 94 addEdge(u, v, c, 0); addEdge(u, v, inf, w); 95 swap(u, v); 96 addEdge(u, v, c, 0); addEdge(u, v, inf, w); 97 } 98 } 99 void solve(int nt, int mt, int ct, int pt) 100 { 101 build(nt, mt, ct, pt); 102 mcmf(0, 2, ct); 103 printf("%d\n", sumFlow); 104 } 105 }my; 106 int main() 107 { 108 int tcase, n, m, c, p; 109 scanf("%d", &tcase); 110 while (tcase--) 111 { 112 scanf("%d%d%d%d",&n, &m, &c, &p); 113 my.solve(n, m, c, p); 114 } 115 return 0; 116 }