题目描述
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。
输入输出格式
输入格式:
输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
输出格式:
输出文件一行包含两个整数,分别表示问题1和问题2的答案。
输入输出样例
输入样例#1:
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
输出样例#1:
13 19
说明
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
解题思路
第一问直接建图求最大流。在建第一问的图时,把边的费用都设为0,因为是原来就有的,不需要扩容。然后第二问,在求完第一问的残留网络上,把每条边都加一条容量为k,费用为各扩容费用的边,因为未加边之前,已经没有增广路了,所以建立一个点n+1,n连n+1,容量为k,费用为0,这就限制了新加入的边只能增加k的流量。然后求一次最小费用,就是最小扩容费用。
代码如下
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <cmath>
#define INF 0x3f3f3f3f
#define maxn 1005
using namespace std;
int s, t;
vector<int> g[maxn];
struct Line{
int r, flow, dis;
bool dir;
Line(int r, int f, int d, int di): r(r), flow(f), dis(d), dir(di){ }
};
vector<Line> line;
void add_line(int x, int y, int f, int d)
{
line.push_back(Line(y, f, d, 1));
g[x].push_back(line.size() - 1);
line.push_back(Line(x, 0, -d, 0));
g[y].push_back(line.size() - 1);
}
int pre[maxn], edge[maxn];
int flow[maxn], dis[maxn];
bool spfa()
{
bool vis[maxn] = {0};
memset(pre, -1, sizeof(pre));
memset(flow, 0x7f, sizeof(flow));
memset(dis, 0x7f, sizeof(dis));
queue<int> que;
que.push(s);
vis[s] = true;
dis[s] = 0;
while(!que.empty()){
int top = que.front();
que.pop();
vis[top] = false;
for(int i = 0; i < g[top].size(); i ++){
int z = g[top][i];
int r = line[z].r;
if(line[z].flow && dis[top] + line[z].dis < dis[r]){
dis[r] = dis[top] + line[z].dis;
flow[r] = min(flow[top], line[z].flow);
pre[r] = top;
edge[r] = z;
if(!vis[r]){
vis[r] = true;
que.push(r);
}
}
}
}
return pre[t] != -1;
}
int max_flow;
int min_dis;
void EK()
{
max_flow = 0;
min_dis = 0;
while(spfa()){
max_flow += flow[t];
min_dis += flow[t] * dis[t];
int now = t;
while(pre[now] != -1){
line[edge[now]].flow -= flow[t];
line[edge[now]^1].flow += flow[t];
now = pre[now];
}
}
}
int a[5005][10];
int main()
{
int n, m, k;
while(cin >> n >> m >> k){
s = 1;
t = n;
for(int i = 0; i < m; i ++){
int u, v, c, w;
cin >> u >> v >> c >> w;
add_line(u, v, c, 0);
a[i][0] = u; a[i][1] = v; a[i][2] = c; a[i][3] = w;
}
EK();
cout << max_flow << " ";
for(int i = 0; i < m; i ++){
add_line(a[i][0], a[i][1], k, a[i][3]);
}
t = n + 1;
add_line(n, t, k, 0);
EK();
cout << min_dis << endl;
for(int i = s; i <= t; i ++)
g[i].clear();
line.clear();
}
return 0;
}