您的位置:首页 > 理论基础 > 计算机网络

BZOJ 1834: [ZJOI2010]network 网络扩容(最大流+最小费用最大流)

2015-03-29 11:12 471 查看


第一问直接跑最大流.然后将所有边再加一次,费用为扩容费用,容量为k,再从一个超级源点连一条容量为k,费用为0的边到原源点,从原汇点连一条同样的边到超级汇点,然 后跑最小费用最大流就OK了.

------------------------------------------------------------------------------------

#include<cstdio>#include<cstring>#include<iostream>#include<vector>#include<algorithm>#include<queue> #define rep(i,n) for(int i=0;i<n;++i)#define clr(x,c) memset(x,c,sizeof(x))#define Rep(i,l,r) for(int i=l;i<r;++i) using namespace std; const int maxn=1005,maxm=5005;const int inf=0x7fffffff; vector<int> g[maxn];int d[maxn];int cur[maxn];int num[maxn];int p[maxn];int a[maxn];int inq[maxn];int u[maxm],v[maxm],c[maxm];int n,m,s,t,k; struct Edge { int from,to,cap,flow,cost; Edge(int u,int v,int c,int f,int w): from(u),to(v),cap(c),flow(f),cost(w) {}}; vector<Edge> edges; void addEdge(int u,int v,int cap,int cost) { edges.push_back( (Edge) {u,v,cap,0,cost} ); edges.push_back( (Edge) {v,u,0,0,-cost} ); int M=edges.size(); g[u].push_back(M-2); g[v].push_back(M-1);} int augment() { int a=inf,x=t; while(x!=s) { Edge &e=edges[p[x]]; a=min(a,e.cap-e.flow); x=e.from; } x=t; while(x!=s) { Edge &e=edges[p[x]]; e.flow+=a; edges[p[x]^1].flow-=a; x=e.from; } return a;} int maxFlow() { int flow=0; clr(d,0); clr(cur,0); clr(num,0); num[0]=n; int x=s; while(d[s]<n) { if(x==t) { flow+=augment(); x=s; } int ok=0; Rep(i,cur[x],g[x].size()) { Edge &e=edges[g[x][i]]; if(e.cap>e.flow && d[e.to]+1==d[x]) { ok=1; cur[x]=i; p[e.to]=g[x][i]; x=e.to; break; } } if(!ok) { int M=n-1; rep(i,g[x].size()) { Edge &e=edges[g[x][i]]; if(e.cap>e.flow) M=min(M,d[e.to]); } if(--num[d[x]]==0) break; num[d[x]=M+1]++; cur[x]=0; if(x!=s) x=edges[p[x]].from; } } return flow;} bool spfa(int &flow,int &cost) { rep(i,n) d[i]=inf; clr(inq,0); d[s]=0; inq[s]=1; p[s]=0; a[s]=inf; queue<int> q; q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); inq[x]=0; rep(i,g[x].size()) { Edge &e=edges[g[x][i]]; if(e.cap>e.flow && d[e.to]>d[x]+e.cost) { d[e.to]=d[x]+e.cost; p[e.to]=g[x][i]; a[e.to]=min(a[x],e.cap-e.flow); if(!inq[e.to]) { q.push(e.to); inq[e.to]=1; } } } } if(d[t]==inf) return 0; flow+=a[t]; cost+=d[t]*a[t]; int x=t; while(x!=s) { Edge &e=edges[p[x]]; e.flow+=a[t]; edges[p[x]^1].flow-=a[t]; x=e.from; } return 1;} int minCost() { int flow=0,cost=0; while(spfa(flow,cost)); return cost;} void init() { rep(i,n+2) g[i].clear(); edges.clear();} int main(){ freopen("test.in","r",stdin); freopen("test.out","w",stdout); scanf("%d%d%d",&n,&m,&k); init(); rep(i,m) { int cap; scanf("%d%d%d%d",&u[i],&v[i],&cap,&c[i]); addEdge(--u[i],--v[i],cap,0); } s=0; t=n-1; printf("%d ",maxFlow()); rep(i,m) addEdge(u[i],v[i],k,c[i]); addEdge(n,0,k,0); addEdge(n-1,n+1,k,0); n+=2; s=n-2; t=n-1; printf("%d\n",minCost()); return 0;}

------------------------------------------------------------------------------------

1834: [ZJOI2010]network 网络扩容

Time Limit: 3 Sec Memory Limit: 64 MB
Submit: 1854 Solved: 919
[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

Sample Output

13 19
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10

HINT

Source

Day1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: