[ Z J O I 2010 ] n e t w o r k 网 络 扩 容 [ZJOI2010]network 网络扩容 [ZJOI2010]network网络扩容
Description:
- 给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。
Input Format:
- 输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
Output Format:
- 输出文件一行包含两个整数,分别表示问题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
TJ:
问题分为两个部分,其中第一部分就是裸的最大流,直接写就完事儿了。
第二问其实就是一个费用流的问题了,需要重新构图,要增加K的容量,而现在免费的流量已经用完了,所以要对跑完最大流的图进行重构,重构方式如下:
①将原图中还有容量的边加到重构图中,费用为0,容量为剩余容量
②对于每一条题给的边,加入到重构图中,费用为扩容费用,容量为INF
③将当前的汇点(也就是N点),连接到一个新增节点上,建边,费用为0,容量为K
然后在重构图上跑费用流就好了,此时已经保证重构图的最大流为K了
CODE:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1111;
const int INF = 0x3f3f3f3f;
struct EDGE{
int to,cap,rev,fee;
bool tag;
};
int n,m,k,max_flow,min_fee,rk[MAXN],iter[MAXN],pre[MAXN],eid[MAXN],flow[MAXN],vis[MAXN],dist[MAXN];
vector<EDGE> G[MAXN],rG[MAXN];
void Input_build(){
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=m;i++){
int u,v,c,f;
scanf("%d %d %d %d",&u,&v,&c,&f);
G[u].push_back((EDGE){v,c,(int)G[v].size(),f,true});
G[v].push_back((EDGE){u,0,(int)G[u].size()-1,f,false});
}
}
bool bfs(){
memset(rk,0,sizeof(rk));
memset(iter,0,sizeof(iter));
queue<int> que;
rk[1] = 1;
que.push(1);
while(!que.empty()){
int now = que.front();
que.pop();
for(int i=0;i<(int)G[now].size();i++){
EDGE e = G[now][i];
if(!e.cap||rk[e.to]) continue;
rk[e.to] = rk[now]+1;
que.push(e.to);
}
}
return rk[n]!=0;
}
int dfs(int now,int f){
if(now==n) return f;
for(int &i=iter[now];i<(int)G[now].size();i++){
EDGE &e = G[now][i];
int to = e.to;
if(!e.cap||rk[e.to]!=rk[now]+1) continue;
int d = dfs(to,min(e.cap,f));
if(d){
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
return 0;
}
int Dinic(){
int flow = 0;
while(bfs()){
int d = dfs(1,INF);
while(d){
flow+=d;
d = dfs(1,INF);
}
}
return flow;
}
void rebuild(){
for(int i=1;i<=n;i++){
for(int j=0;j<(int)G[i].size();j++){
EDGE e = G[i][j];
if(!e.tag) continue;
if(e.cap){
rG[i].push_back((EDGE){e.to,e.cap,(int)rG[e.to].size(),0,true});
rG[e.to].push_back((EDGE){i,0,(int)rG[i].size()-1,0,true});
}
rG[i].push_back((EDGE){e.to,INF,(int)rG[e.to].size(),e.fee,true});
rG[e.to].push_back((EDGE){i,0,(int)rG[i].size()-1,-e.fee,true});
}
}
rG[n].push_back((EDGE){n+1,k,(int)rG[n+1].size(),0,true});
rG[n+1].push_back((EDGE){n,0,(int)rG[n].size()-1,0,true});
}
bool Dijkstra(){
memset(dist,INF,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[1] = 0; flow[1] = INF;
pre[n] = 0; pre[1] = 0;
while(true){
int pos = -1;
for(int i=1;i<=n;i++) if(!vis[i]&&(pos==-1||dist[i]<dist[pos])) pos = i;
if(pos==-1) break;
vis[pos] = 1;
for(int i=0;i<(int)rG[pos].size();i++){
EDGE &e = rG[pos][i];
if(!e.cap) continue;
if(dist[pos]+e.fee<dist[e.to]){
dist[e.to] = dist[pos]+e.fee;
pre[e.to] = pos;
eid[e.to] = i;
flow[e.to] = min(e.cap,flow[pos]);
}
}
}
return pre[n]!=0;
}
int mincost_maxflow(){
n++;
int cost = 0;
while(Dijkstra()){
int rt = n;
while(rt!=1){
EDGE &e = rG[pre[rt]][eid[rt]];
cost+=e.fee*flow[n];
e.cap-=flow[n];
rG[e.to][e.rev].cap+=flow[n];
rt = pre[rt];
}
}
return cost;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1834/6.in","r",stdin);
#endif
Input_build();
max_flow = Dinic();
rebuild();
min_fee = mincost_maxflow();
printf("%d %d\n",max_flow,min_fee);
#ifndef ONLINE_JUDGE
freopen("1834/6.out","r",stdin);
scanf("%d %d",&max_flow,&min_fee);
printf("RESAULT:%d %d\n",max_flow,min_fee);
#endif
return 0;
}