P2604 [ZJOI2010]網路擴容 費用流
阿新 • • 發佈:2020-11-17
P2604 [ZJOI2010]網路擴容(https://www.luogu.com.cn/problem/P2604)
題目描述
給定一張有向圖,每條邊都有一個容量 cc 和一個擴容費用 ww。這裡擴容費用是指將容量擴大 11 所需的費用。求:
在不擴容的情況下,1 到 n 的最大流;
將 1 到 n 的最大流增加 k 所需的最小擴容費用。
輸入格式
第一行包含三個整數 n,m,k,表示有向圖的點數、邊數以及所需要增加的流量。
接下來的 M 行每行包含四個整數 u,v,c,w,表示一條從u 到 v,容量為 c,擴容費用為 w 的邊。
輸出格式
輸出檔案一行包含兩個整數,分別表示問題 1 和問題 2 的答案。
輸入輸出樣例
輸入
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
輸出
13 19
說明/提示
資料規模與約定
對於 30% 的資料,保證 n≤100。
對於 100% 的資料,保證 1≤n≤10^3, 1≤m≤5×10^3,1≤k≤10,1≤u,v≤n。
思路
第一問裸的最大流。
第二問,我們在題目中的圖,每條邊u-v建立一條流量為INF,費用為w的邊。用來擴容。
新建一個原點0,0-n建一條流量為k的邊。跑最小費用最大流就可以了。
#include<bits/stdc++.h> #define re register using namespace std; const int maxn = 1000 + 10; const int maxm=1e6+10; const int inf=1<<30; const int INF = 0x3f3f3f3f; struct po { int to,dis,nxt,w; } edge[maxm<<1]; struct max_folw { int dis[maxn]; int vis[maxn]; int head[maxn]; int n,s,t,cut=-1; int ans=0, fy=0; void init(int N, int S, int T) { ans=0, fy=0; cut=-1; n=N, s=S, t=T; memset(head, -1, sizeof(head)); } void add_edge(int from,int to,int w,int dis) { edge[++cut].nxt=head[from]; edge[cut].to=to; edge[cut].w=w; edge[cut].dis=dis; head[from]=cut; } void add(int from,int to,int w,int dis) { add_edge(from,to,w,dis); add_edge(to,from,0,-dis); } bool spfa() { memset(vis,0,sizeof(vis)); for(re int i=0; i<=n; i++) dis[i]=inf; dis[t]=0; vis[t]=1; deque<int> q; q.push_back(t); while(!q.empty()) { int u=q.front(); vis[u]=0; q.pop_front(); for(re int i=head[u]; i!=-1; i=edge[i].nxt) { int v=edge[i].to; if(edge[i^1].w>0&&dis[v]>dis[u]-edge[i].dis) { dis[v]=dis[u]-edge[i].dis; if(!vis[v]) { vis[v]=1; if(!q.empty()&&dis[v]<dis[q.front()]) q.push_front(v); else q.push_back(v); } } } } return dis[s]<inf; } int dfs(int u,int low) { if(u==t) { vis[t]=1; return low; } int diss=0; vis[u]=1; for(re int i=head[u]; i!=-1; i=edge[i].nxt) { int v=edge[i].to; if(!vis[v]&&edge[i].w!=0&&dis[u]-edge[i].dis==dis[v]) { int check=dfs(v,min(edge[i].w,low)); if(check>0) { fy+=check*edge[i].dis; edge[i].w-=check; edge[i^1].w+=check; low-=check; diss+=check; if(low==0) break; } } } return diss; } void max_flow() { while(spfa()) { //流量+k vis[t]=1; while(vis[t]) { memset(vis,0,sizeof(vis)); ans+=dfs(s,inf); } } } } flow; int x[5005], y[5005], z[5005], w[5005]; int main() { int n, m, k; scanf("%d%d%d", &n, &m, &k); flow.init(n+5, 1, n); for(int i=1; i<=m; i++){ scanf("%d%d%d%d", &x[i], &y[i], &z[i], &w[i]); flow.add(x[i], y[i], z[i], 0); } flow.max_flow(); int mx=flow.ans; printf("%d ", mx); flow.init(n+5, 0, n); for(int i=1; i<=m; i++){ flow.add(x[i], y[i], z[i], 0); flow.add(x[i], y[i], inf, w[i]); } flow.add(0, 1, k+mx, 0); flow.max_flow(); printf("%d\n", flow.fy); return 0; }