1. 程式人生 > >[ZJOI2010]網絡擴容 (最大流 + 費用流)

[ZJOI2010]網絡擴容 (最大流 + 費用流)

表示 img 容量 one != ++ clu pop pla

題目描述

給定一張有向圖,每條邊都有一個容量C和一個擴容費用W。這裏擴容費用是指將容量擴大1所需的費用。求: 1、 在不擴容的情況下,1到N的最大流; 2、 將1到N的最大流增加K所需的最小擴容費用。

輸入輸出格式

輸入格式:

輸入文件的第一行包含三個整數N,M,K,表示有向圖的點數、邊數以及所需要增加的流量。 接下來的M行每行包含四個整數u,v,C,W,表示一條從u到v,容量為C,擴容費用為W的邊。

輸出格式:

輸出文件一行包含兩個整數,分別表示問題1和問題2的答案。

輸入輸出樣例

輸入樣例#1:
5 8 2
1 2 5 8
2 5 9 9
5 1 6 2
5 1 1 8
1 2 8 7
2 5 4 9
1 2 1 1
1 4 2 1
輸出樣例#1:
13 19

說明

30%的數據中,N<=100

100%的數據中,N<=1000,M<=5000,K<=10

集最大流和費用流與一身。。。。

擴容的時候 只需要從0建一條向1流量為k的邊 費用為0

其他邊之間的流量為INF 費用不變

技術分享
  1 /*
  2     有重邊對 max_flow()中找前驅有影響 
  3     所以在node中記錄前驅就好了 
  4 */
  5 #include<queue>
  6 #include<cstdio>
  7 #include<cstring>
  8
#include<iostream> 9 #define MAXN 200010 10 11 using namespace std; 12 13 const int INF=0x7fffffff; 14 15 int n,m,k,MAX_FLOW,MIN_FEE,src; 16 17 int x,y,val,cost[MAXN],a[MAXN]; 18 19 struct node { 20 int from; 21 int to; 22 int next; 23 int val; 24
int cost; 25 int save; 26 }; 27 node e[MAXN]; 28 29 bool vis[MAXN]; 30 31 int head[MAXN],tot=1; 32 33 int fee[MAXN],pre[MAXN]; 34 35 queue<int> q; 36 37 inline void read(int&x) { 38 int f=1;x=0;char c=getchar(); 39 while(c>9||c<0) {if(c==-) f=-1;c=getchar();} 40 while(c>=0&&c<=9) {x=(x<<1)+(x<<3)+c-48;c=getchar();} 41 x=x*f; 42 } 43 44 inline void add(int x,int y,int val,int cost) { 45 e[++tot].to=y; 46 e[tot].from=x; 47 e[tot].val=val; 48 e[tot].cost=cost; 49 e[tot].next=head[x]; 50 head[x]=tot; 51 } 52 53 inline void add1(int x,int y,int val,int save) { 54 e[++tot].to=y; 55 e[tot].from=x; 56 e[tot].val=val; 57 e[tot].save=save; 58 e[tot].next=head[x]; 59 head[x]=tot; 60 } 61 62 inline void add_edge(int x,int y,int val,int cost) { 63 add(x,y,val,cost); 64 add(y,x,0,-cost); 65 } 66 67 inline void add_edge1(int x,int y,int val,int cost) { 68 add1(x,y,val,cost); 69 add1(y,x,0,-cost); 70 } 71 72 inline bool spfa_flow() { 73 for(int i=0;i<=n;i++) vis[i]=false,pre[i]=-1; 74 while(!q.empty()) q.pop(); 75 q.push(src); 76 fee[src]=0; 77 pre[src]=0; 78 vis[src]=true; 79 while(!q.empty()) { 80 int u=q.front(); 81 q.pop(); 82 for(int i=head[u];i;i=e[i].next) { 83 int to=e[i].to; 84 if(!vis[to]&&e[i].val) { 85 pre[to]=i; 86 vis[to]=true; 87 if(to==n) return true; 88 q.push(to); 89 } 90 } 91 } 92 return false; 93 } 94 95 inline int max_flow() { 96 int flow=INF; 97 for(int i=pre[n];i;i=pre[e[i^1].to]) 98 flow=min(flow,e[i].val); 99 for(int i=pre[n];i;i=pre[e[i^1].to]) 100 e[i].val-=flow,e[i^1].val+=flow; 101 return flow; 102 } 103 104 inline void change() { 105 int pot=tot; 106 for(int i=4;i<=pot;i++) 107 if(i%2==0) add_edge(e[i].from,e[i].to,INF,e[i].save); 108 e[2].val=k; 109 e[3].val=0; 110 return; 111 } 112 113 inline bool spfa_fee() { 114 for(int i=0;i<=n;i++) vis[i]=false,pre[i]=-1,fee[i]=INF; 115 while(!q.empty()) q.pop(); 116 q.push(0); 117 fee[0]=0; 118 vis[0]=true; 119 pre[0]=0; 120 a[0]=999999; 121 while(!q.empty()) { 122 int u=q.front(); 123 q.pop(); 124 vis[u]=false; 125 for(int i=head[u];i!=-1;i=e[i].next) { 126 int to=e[i].to; 127 if(fee[to]>fee[u]+e[i].cost&&e[i].val>0) { 128 a[to]=min(a[u],e[i].val); 129 fee[to]=fee[u]+e[i].cost; 130 pre[to]=i; 131 if(!vis[to]) { 132 vis[to]=true; 133 q.push(to); 134 } 135 } 136 } 137 } 138 return fee[n]!=INF; 139 } 140 141 inline int MIN_fee() { 142 int Flow=INF; 143 for(int i=pre[n];i;i=pre[e[i].from]) 144 Flow=min(Flow,e[i].val); 145 for(int i=pre[n];i;i=pre[e[i].from]) 146 e[i].val-=Flow,e[i^1].to+=Flow; 147 return Flow; 148 } 149 150 int main() { 151 read(n);read(m);read(k); 152 memset(head,-1,sizeof head); 153 add_edge1(src,1,1<<30,0); 154 for(int i=1;i<=m;i++) { 155 read(x);read(y);read(val);read(cost[i]); 156 add_edge1(x,y,val,cost[i]); 157 } 158 while(spfa_flow()) 159 MAX_FLOW+=max_flow(); 160 change(); 161 while(spfa_fee()) { 162 int FLOW=MIN_fee(); 163 MIN_FEE+=FLOW*fee[n]; 164 } 165 printf("%d %d\n",MAX_FLOW,MIN_FEE); 166 return 0; 167 }
代碼

[ZJOI2010]網絡擴容 (最大流 + 費用流)