[BZOJ1834][ZJOI2010]network 网络扩容 最大流+费用流
1834: [ZJOI2010]network 网络扩容
Time Limit: 3 Sec Memory Limit: 64 MB Submit: 3330 Solved: 1739 [Submit][Status][Discuss]Description
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。
Input
输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
Output
输出文件一行包含两个整数,分别表示问题1和问题2的答案。
Sample Input
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 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
Sample Output
13 19
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
对于第一问,我们直接跑网络流。
对于第二问,我们先建一个超级源,从这个超级源向1连一条容量为k,费用为0的边。
之后对于原图的每一条边,建一条容量无限的边,跑最小费用最大流即可。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #define maxm 5005 8 #define maxn 1005 9 using namespace std; 10 struct data { 11 int from,to,next,w,c; 12 }e[maxm*4]; 13 int head[maxn],cnt; 14 void add(int u,int v,int w,int c){e[cnt].from=u;e[cnt].next=head[u];e[cnt].to=v;e[cnt].w=w;e[cnt].c=c;head[u]=cnt++;} 15 int n,m,k; 16 int q[maxn]; 17 bool vis[maxn]; 18 int dis[maxn]; 19 bool bfs() { 20 memset(dis,-1,sizeof(dis)); 21 int h=0,t=1; 22 q[h]=1; 23 vis[1]=1; 24 dis[1]=0; 25 while(h!=t) { 26 int now=q[h];h++;vis[now]=0;if(h==1000) h=0; 27 for(int i=head[now];i>=0;i=e[i].next) { 28 int to=e[i].to; 29 if(e[i].w&&dis[to]<0) { 30 dis[to]=dis[now]+1; 31 if(!vis[to]){ 32 vis[to]=1; 33 q[t++]=to;if(t==1000)t=0; 34 } 35 } 36 } 37 } 38 return dis[n]!=-1; 39 } 40 int dfs(int now,int a) { 41 if(now==n||a==0) return a; 42 int flow=0,f; 43 for(int i=head[now];i>=0;i=e[i].next) { 44 int to=e[i].to; 45 if(dis[to]==dis[now]+1&&e[i].w>0) { 46 f=dfs(to,min(a,e[i].w)); 47 e[i].w-=f; 48 e[i^1].w+=f; 49 flow+=f; 50 a-=f; 51 if(a==0) return flow; 52 } 53 } 54 if(!flow) dis[now]=-1; 55 return flow; 56 } 57 void work1() { 58 int ans=0; 59 while(bfs()){ans+=dfs(1,2147483647);} 60 printf("%d ",ans); 61 } 62 int cost=0; 63 bool spfa() { 64 for(int i=0;i<=n;i++) dis[i]=-1000000000; 65 int h=0,t=1; 66 q[h]=n; 67 vis[n]=1; 68 dis[n]=0; 69 while(h!=t) { 70 int now=q[h];h++;vis[now]=0;if(h==1000) h=0; 71 for(int i=head[now];i>=0;i=e[i].next) { 72 int to=e[i].to; 73 if(e[i^1].w&&dis[to]<dis[now]+e[i].c) { 74 dis[to]=dis[now]+e[i].c; 75 if(!vis[to]){ 76 vis[to]=1; 77 q[t++]=to;if(t==1000)t=0; 78 } 79 } 80 } 81 } 82 cost-=dis[0]; 83 return dis[0]!=-1000000000; 84 } 85 int ans2; 86 int zkw(int now,int a) { 87 if(now==n||a==0){ans2+=cost*a;return a;} 88 int flow=0,f;vis[now]=1; 89 for(int i=head[now];i>=0;i=e[i].next) { 90 int to=e[i].to; 91 if(dis[to]==dis[now]+e[i].c&&e[i].w>0&&!vis[to]&&(f=zkw(to,min(a,e[i].w)))) { 92 e[i].w-=f; 93 e[i^1].w+=f; 94 flow+=f; 95 a-=f; 96 if(a==0) break; 97 } 98 } 99 return flow; 100 } 101 void build() { 102 int t=cnt; 103 for(int i=0;i<t;i+=2) { 104 add(e[i].from,e[i].to,1147483647,e[i].c); 105 add(e[i].to,e[i].from,0,-e[i].c); 106 } 107 add(0,1,k,0); 108 add(1,0,0,0); 109 for(int i=0;i<t;i++) e[i].c=0; 110 } 111 void work2() { 112 ans2=0;cost=0; 113 build(); 114 memset(vis,0,sizeof(vis)); 115 while(spfa()) { 116 do { 117 memset(vis,0,sizeof(vis)); 118 }while(zkw(0,2147483647)); 119 memset(vis,0,sizeof(vis));cost=0; 120 } 121 printf("%d",ans2); 122 } 123 int main() { 124 memset(head,-1,sizeof(head)); 125 scanf("%d%d%d",&n,&m,&k); 126 for(int i=1;i<=m;i++) { 127 int u,v,w,c; 128 scanf("%d%d%d%d",&u,&v,&w,&c); 129 add(u,v,w,c);add(v,u,0,-c); 130 } 131 work1(); 132 work2(); 133 }
O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~