【题目】
题目描述:
给定一张有向图,每条边都有一个容量 c c c 和一个扩容费用 w w w 。这里扩容费用是指将容量扩大 1 1 1 所需的费用。求:
- 在不扩容的情况下, 1 1 1 到 n n n 的最大流;
- 将 1 1 1 到 n n n 的最大流增加 k k k 所需的最小扩容费用。
输入格式:
输入的第一行包含三个整数 n n n, m m m, k k k,表示有向图的点数、边数以及所需要增加的流量。
接下来的 m m m 行每行包含四个整数 u u u, v v v, c c c, w w w ,表示一条从 u u u 到 v v v,容量为 c c c,扩容费用为 w w w 的边。
输出格式:
输出文件一行包含两个整数,分别表示问题 1 1 1 和问题 2 2 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
%
30\%
30% 的数据中,
n
≤
100
n\le100
n≤100
100
%
100\%
100% 的数据中,
N
≤
1000
N\le1000
N≤1000;
m
≤
5000
m\le5000
m≤5000;
k
≤
10
k\le10
k≤10
【分析】
对于问题 1 1 1,就是最大流模板,难点在于问题 2 2 2。
第二问相当于就是在最大流为 m a x f l o w maxflow maxflow 的基础上,将最大流调整为 m a x f l o w + k maxflow+k maxflow+k。
因此我们在解决问题 1 1 1 的残余网络上继续解决这道题,在残余网络的基础上,对于每条原图边,都加一条容量为 i n f inf inf,费用为原费用的边。(这样做之后,如果把流量调整到 k k k,那此时跑出的最小费用就是答案)。
由于不扩容的时候最大流已经是 m a x f l o w maxflow maxflow,所以只用在残余网络上多出 k k k 的流量就行了。
现在的问题就是如何控制流量为 k k k。
有一个巧妙的方法,就是建立一个超级源点 s s s,从 s s s 向 1 1 1 连容量 k k k,费用为 0 0 0 的边。
那么从 s s s 开始跑费用流,由于残余网络上的边权都是 i n f inf inf,一定能流满,那此时最大流就是 k k k,就符合题意了。
【代码】
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10005
#define M 1000005
#define inf (1ll<<31ll)-1
using namespace std;
int n,m,k,s,t,maxflow,mincost,tot=1;
int d[N],f[N],first[N],v[M],w[M],nxt[M],cost[M];
bool vis[N],walk[N];
struct edge{int u,v,f,c;}e[M];
void add(int x,int y,int f,int c)
{
nxt[++tot]=first[x];
first[x]=tot,v[tot]=y,w[tot]=f,cost[tot]=c;
}
bool bfs(int s)
{
int x,y,i;
memset(d,0x3f,sizeof(d));
memcpy(f,first,sizeof(f));
memset(vis,false,sizeof(vis));
memset(walk,false,sizeof(walk));
queue<int>q;q.push(s);d[s]=0;
while(!q.empty())
{
x=q.front();
vis[x]=false,q.pop();
for(i=f[x];i;i=nxt[i])
{
y=v[i];
if(w[i]&&d[y]>d[x]+cost[i])
{
d[y]=d[x]+cost[i];
if(!vis[y]) q.push(y),vis[y]=true;
}
}
}
return d[n]!=0x3f3f3f3f;
}
int dinic(int now,int flow)
{
if(now==n)
return mincost+=flow*d[n],flow;
int x,delta,ans=0;
walk[now]=true;
for(int &i=f[now];i;i=nxt[i])
{
x=v[i];
if(w[i]&&!walk[x]&&d[x]==d[now]+cost[i])
{
delta=dinic(x,min(flow,w[i]));
w[i]-=delta,w[i^1]+=delta,flow-=delta,ans+=delta;
if(!flow) return ans;
}
}
return ans;
}
int main()
{
int i;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=m;++i)
{
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].f,&e[i].c);
add(e[i].u,e[i].v,e[i].f,0),add(e[i].v,e[i].u,0,0);
}
while(bfs(1)) maxflow+=dinic(1,inf);
add(s,1,k,0),add(1,s,0,0);
for(i=1;i<=m;++i) add(e[i].u,e[i].v,inf,e[i].c),add(e[i].v,e[i].u,0,-e[i].c);
while(bfs(s)) dinic(s,inf);
printf("%d %d",maxflow,mincost);
return 0;
}