给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将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%的数据中,N<=1000,M<=5000,K<=10
Day1
第二问,可以在跑完第一问的基础上在所有边上建流量INF,费用 wi 的边,表示对此边扩建所需费用,然后再加个源点限流,跑一遍最小费用最大流就行了。
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 1000000010;
const int SZ = 1000010;
int head[SZ],nxt[SZ],tot = 1;
struct edge{
int f,t,d,c;
}l[SZ];
void build(int f,int t,int d,int c)
{
l[++ tot].t = t;
l[tot].f = f;
l[tot].c = c;
l[tot].d = d;
nxt[tot] = head[f];
head[f] = tot;
}
void insert(int f,int t,int d,int c)
{
build(f,t,d,c); build(t,f,0,-c);
}
int dist[SZ];
queue<int> q;
bool use[SZ];
int pre[SZ];
bool spfa(int s,int e)
{
memset(dist,63,sizeof(dist));
dist[s] = 0;
q.push(s);
use[s] = 1;
while(q.size())
{
int f = q.front(); q.pop();
use[f] = 0;
for(int i = head[f];i;i = nxt[i])
{
int v = l[i].t;
if(dist[v] > dist[f] + l[i].c && l[i].d)
{
dist[v] = dist[f] + l[i].c;
pre[v] = i;
if(!use[v])
{
use[v] = 1;
q.push(v);
}
}
}
}
if(dist[e] > INF) return false;
return true;
}
int dfs(int u,int e,int d)
{
int x = INF,ans = 0;
for(int i = pre[e];i;i = pre[l[i].f])
x = min(x,l[i].d);
for(int i = pre[e];i;i = pre[l[i].f])
ans += l[i].c * x,l[i].d -= x,l[i ^ 1].d += x;
if(d == 1) return x;
return ans;
}
int ek(int s,int e,int d)
{
int ans = 0;
while(spfa(s,e)) ans += dfs(s,e,d);
return ans;
}
int ff[SZ],tt[SZ],dd[SZ],ww[SZ];
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= m;i ++)
{
scanf("%d%d%d%d",&ff[i],&tt[i],&dd[i],&ww[i]);
insert(ff[i],tt[i],dd[i],0);
}
printf("%d ",ek(1,n,1));
int s = n + 1;
insert(s,1,k,0);
for(int i = 1;i <= m;i ++)
{
insert(ff[i],tt[i],INF,ww[i]);
}
printf("%d",ek(s,n,2));
return 0;
}