【费用流】bzoj1834: [ZJOI2010]network 网络扩容
还是稍微记一下这个拆点模型吧
Description
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。
求:
1、在不扩容的情况下,1到N的最大流;
2、将1到N的最大流增加K所需的最小扩容费用。
Input
第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。
接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
N<=1000,M<=5000,K<=10
Output
输出文件一行包含两个整数,分别表示问题1和问题2的答案。
题目分析
这里只考虑第二问:第一眼看上去像是二分或者最小费用可行流。然而在残量网络里将源点拆为$S$和$S‘$再连$(S,S',K,0)$的边来限制图中新增的费用是一种更好的模型。
以后再遇到个数限制时候,要及时想到 拆点 的这一类处理方式。
1 #include<bits/stdc++.h> 2 //const int maxn = 1035; 3 const int maxm = 20035; 4 const int maxNode = 1035; 5 const int INF = 2e9; 6 7 struct Edge 8 { 9 int u,v,f,c,cst; 10 Edge(int a=0, int b=0, int c=0, int d=0, int e=0):u(a),v(b),f(c),c(d),cst(e) {} 11 }edges[maxm],sv[maxm]; 12 int n,m,K,ans1,ans2,S,T,SS; 13 int edgeTot,head[maxNode],nxt[maxm],bck[maxNode],cst[maxNode],flw[maxNode]; 14 bool inq[maxNode]; 15 16 int read() 17 { 18 char ch = getchar(); 19 int num = 0, fl = 1; 20 for (; !isdigit(ch); ch=getchar()) 21 if (ch=='-') fl = -1; 22 for (; isdigit(ch); ch=getchar()) 23 num = (num<<1)+(num<<3)+ch-48; 24 return num*fl; 25 } 26 void addedge(int u, int v, int c, int cst) 27 { 28 edges[edgeTot] = Edge(u, v, 0, c, cst), nxt[edgeTot] = head[u], head[u] = edgeTot, ++edgeTot; 29 edges[edgeTot] = Edge(v, u, 0, 0, -cst), nxt[edgeTot] = head[v], head[v] = edgeTot, ++edgeTot; 30 } 31 std::pair<int, int> maxFlow() 32 { 33 int flow = 0, cost = 0; 34 for (;;) 35 { 36 std::queue<int> q; 37 memset(bck, 0, sizeof bck); 38 memset(flw, 0, sizeof flw); 39 memset(cst, 0x3f3f3f3f, sizeof cst); 40 q.push(S), cst[S] = 0, flw[S] = INF; 41 for (int tmp; q.size(); ) 42 { 43 tmp = q.front(), q.pop(), inq[tmp] = 0; 44 for (int i=head[tmp]; i!=-1; i=nxt[i]) 45 { 46 int v = edges[i].v; 47 if (cst[v] > cst[tmp]+edges[i].cst&&edges[i].f < edges[i].c){ 48 cst[v] = cst[tmp]+edges[i].cst, bck[v] = i; 49 flw[v] = std::min(flw[tmp], edges[i].c-edges[i].f); 50 if (!inq[v]) q.push(v), inq[v] = 1; 51 } 52 } 53 } 54 if (!flw[T]) break; 55 for (int i=T; i!=S; i=edges[bck[i]].u) 56 edges[bck[i]].f += flw[T], edges[bck[i]^1].f -= flw[T]; 57 flow += flw[T], cost += flw[T]*cst[T]; 58 } 59 return std::make_pair(flow, cost); 60 } 61 int main() 62 { 63 memset(head, -1, sizeof head); 64 n = read(), m = read(), K = read(); 65 for (int i=1; i<=m; i++) 66 { 67 int u = read(), v = read(), c = read(), cst = read(); 68 sv[i] = Edge(u, v, 0, c, cst), addedge(u, v, c, 0); 69 } 70 SS = 0, S = 1, T = n; 71 ans1 = maxFlow().first; 72 std::swap(S, SS); 73 addedge(S, SS, K, 0); 74 for (int i=1; i<=m; i++) 75 addedge(sv[i].u, sv[i].v, INF, sv[i].cst); 76 ans2 = maxFlow().second; 77 printf("%d %d\n",ans1,ans2); 78 return 0; 79 }
END