【bzoj1834】[ZJOI2010]network 网络扩容
1834: [ZJOI2010]network 网络扩容
Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 2701 Solved: 1368
[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
【题解】
网络流和费用流的结合。
第一问很简单,直接跑一遍dinic即可。
第二问是费用流,将原图上的每条边上建立一条附属边,流量为k,费用为扩容费用,然后跑费用流即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<ctime> 7 #include<algorithm> 8 #include<queue> 9 using namespace std; 10 #define INF 1000000000 11 #define MAXN 5010 12 struct node{int x,y,next,v,c,rel;}e[MAXN*10],edge[MAXN*10]; 13 int n,m,k,len,ans,Link[MAXN],level[MAXN],vis[MAXN],dis[MAXN],lastnode[MAXN],lastedge[MAXN],q[MAXN*10]; 14 inline int read() 15 { 16 int x=0,f=1; char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} 19 return x*f; 20 } 21 void insert(int x,int y,int v,int c) 22 { 23 e[++len].next=Link[x];Link[x]=len;e[len].x=x;e[len].y=y;e[len].v=v;e[len].c=c;e[len].rel=len+1; 24 e[++len].next=Link[y];Link[y]=len;e[len].x=y;e[len].y=x;e[len].v=0;e[len].c=-c;e[len].rel=len-1; 25 } 26 bool bfs() 27 { 28 memset(level,-1,sizeof(level)); 29 int head=0,tail=1; q[1]=1; level[1]=0; 30 while(++head<=tail) 31 for(int i=Link[q[head]];i;i=e[i].next) 32 if(level[e[i].y]<0&&e[i].v) 33 { 34 q[++tail]=e[i].y; 35 level[q[tail]]=level[q[head]]+1; 36 } 37 return level[n]>=0; 38 } 39 int dinic(int x,int flow) 40 { 41 if(x==n) return flow; 42 int maxflow=0,d=0; 43 for(int i=Link[x];i&&maxflow<flow;i=e[i].next) 44 if(level[e[i].y]==level[x]+1&&e[i].v) 45 if(d=dinic(e[i].y,min(e[i].v,flow-maxflow))) 46 { 47 maxflow+=d; 48 e[i].v-=d; 49 e[e[i].rel].v+=d; 50 } 51 if(!maxflow) level[x]=-1; 52 return maxflow; 53 } 54 void solve1() 55 { 56 int d=0; 57 ans=0; 58 while(bfs()) 59 while(d=dinic(1,INF)) 60 ans+=d; 61 printf("%d ",ans); 62 } 63 bool spfa() 64 { 65 memset(vis,0,sizeof(vis)); 66 memset(dis,10,sizeof(dis)); 67 int head=0,tail=1,oo=dis[0]; 68 q[1]=1; vis[1]=1; dis[1]=0; 69 while(++head<=tail) 70 { 71 int x=q[head]; 72 for(int i=Link[x];i;i=e[i].next) 73 if(dis[x]+e[i].c<dis[e[i].y]&&e[i].v) 74 { 75 dis[e[i].y]=dis[x]+e[i].c; 76 if(!vis[e[i].y]) 77 { 78 q[++tail]=e[i].y; 79 vis[e[i].y]=1; 80 } 81 lastnode[e[i].y]=x; lastedge[e[i].y]=i; 82 } 83 vis[x]=0; 84 } 85 return dis[n]<oo; 86 } 87 void cost() 88 { 89 int d=k; 90 for(int i=n;i!=1;i=lastnode[i]) 91 if(e[lastedge[i]].v<d) 92 d=e[lastedge[i]].v; 93 for(int i=n;i!=1;i=lastnode[i]) 94 { 95 int j=lastedge[i]; 96 e[j].v-=d; 97 e[e[j].rel].v+=d; 98 ans+=d*e[j].c; 99 } 100 k-=d; 101 } 102 void solve2() 103 { 104 ans=0; 105 while(k)//控制1点的流量,相当于一个超级源的作用 106 { 107 spfa(); 108 cost(); 109 } 110 printf("%d\n",ans); 111 } 112 int main() 113 { 114 freopen("cin.in","r",stdin); 115 freopen("cout.out","w",stdout); 116 n=read(); m=read(); k=read(); 117 for(int i=1;i<=m;i++) 118 { 119 int x=read(),y=read(),v=read(),c=read(); 120 insert(x,y,v,0); 121 edge[i].x=x; edge[i].y=y; edge[i].c=c; 122 } 123 solve1(); 124 for(int i=1;i<=m;i++) insert(edge[i].x,edge[i].y,k,edge[i].c); 125 solve2(); 126 return 0; 127 }