[题目]
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。
[算法]
最大流,最小费用最大流
[分析]
最大流isap或dinic不必说,然后把每条边重新加入图中,有费用且容量为INF,模拟扩容的过程。再新建一个超级源,与1连一条费用0,容量k的边,跑最小费用最大流即可
[注意]
再跑最小费用最大流之前,原来的图是不能删的!要理解清楚每一步的含义……
[代码]
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
#define MAXN 2000
#define MAXM 30000
#define INF 1000000000
int totNode = 0;
int totEdge;
int point[MAXN], next[MAXM], v[MAXM], flow[MAXM], cap[MAXM], w[MAXM];
int dis[MAXN], lastedge[MAXN], deep[MAXN], num[MAXN], cur[MAXN];
int u[MAXM], vv[MAXM], cost[MAXM];
bool check[MAXN];
int n, m, k;
inline void addedge(int x, int y, int theCap, int theCost)
{
totEdge++;
next[totEdge] = point[x]; point[x] = totEdge; v[totEdge] = y;
flow[totEdge] = 0; cap[totEdge] = theCap; w[totEdge] = theCost;
totEdge++;
next[totEdge] = point[y]; point[y] = totEdge; v[totEdge] = x;
flow[totEdge] = 0; cap[totEdge] = 0; w[totEdge] = -theCost;
}
inline void clear()
{
totEdge = -1;
memset(point, -1, sizeof(point));
memset(next, -1, sizeof(next));
}
inline int addflow(int start, int end)
{
int ans = INF;
int now = end;
while (now != start)
{
int temp = lastedge[now];
ans = min(ans, cap[temp] - flow[temp]);
now = v[temp^1];
}
now = end;
while (now != start)
{
int temp = lastedge[now];
flow[temp] += ans;
flow[temp^1] -= ans;
now = v[temp^1];
}
return ans;
}
inline void bfs(int start, int end)
{
queue<int> q;
while (!q.empty()) q.pop();
memset(check, 0, sizeof(check));
memset(deep, 0, sizeof(deep));
q.push(end); deep[end] = 0; check[end] = true;
while (!q.empty())
{
int now = q.front(); q.pop();
for (int temp = point[now]; temp != -1; temp = next[temp])
{
int tt = temp ^ 1;
if (!check[v[tt]] && flow[tt] < cap[tt])
{
deep[v[tt]] = deep[now] + 1;
q.push(v[tt]);
check[v[tt]] = true;
}
}
}
}
inline int isap(int start, int end)
{
int ans = 0;
int now = start;
memset(num, 0, sizeof(num));
bfs(start, end);
for (int i = 1; i <= totNode; i++)
{
cur[i] = point[i];
num[deep[i]]++;
}
while (deep[start] < totNode)
{
if (now == end)
{
ans += addflow(start, end);
now = start;
}
bool isok = false;
for (int temp = cur[now]; temp != -1; temp = next[temp])
if (deep[now] == deep[v[temp]] + 1 && flow[temp] < cap[temp])
{
isok = true;
lastedge[v[temp]] = temp;
cur[now] = temp;
now = v[temp];
break;
}
if (!isok)
{
int minn = totNode - 1;
for (int temp = point[now]; temp != -1; temp = next[temp])
if (flow[temp] < cap[temp])
minn = min(minn, deep[v[temp]]);
if (--num[deep[now]] == 0) break;
num[deep[now] = minn + 1]++;
cur[now] = point[now];
if (now != start) now = v[lastedge[now]^1];
}
}
return ans;
}
inline bool spfa(int start, int end, int &maxflow, int &mincost)
{
queue<int> q;
while (!q.empty()) q.pop();
memset(dis, 0x7f, sizeof(dis));
memset(check, 0, sizeof(check));
dis[start] = 0; q.push(start); check[start] = true;
while (!q.empty())
{
int now = q.front(); q.pop();
check[now] = false;
for (int temp = point[now]; temp != -1; temp = next[temp])
if (flow[temp] < cap[temp] && dis[now] + w[temp] < dis[v[temp]])
{
dis[v[temp]] = dis[now] + w[temp];
lastedge[v[temp]] = temp;
if (!check[v[temp]])
{
check[v[temp]] = true;
q.push(v[temp]);
}
}
}
if (dis[end] > INF) return false;
int theAdd = addflow(start, end);
maxflow += theAdd; mincost += theAdd * dis[end];
return true;
}
int SolveMinCost(int start, int end)
{
int mincost = 0, maxflow = 0;
while (spfa(start, end, maxflow, mincost))
{
int debug = 1;
debug = debug + 1;
}
return mincost;
}
int main()
{
//freopen("input.txt","r",stdin);
scanf("%d%d%d", &n, &m, &k);
clear();
for (int i = 1; i <= m; i++)
{
int tempCap;
scanf("%d%d%d%d", &u[i], &vv[i], &tempCap, &cost[i]);
addedge(u[i], vv[i], tempCap, 0);
}
totNode = n;
printf("%d ", isap(1, n));
for (int i = 1; i <= m; i++)
addedge(u[i], vv[i], INF, cost[i]);
totNode++;
addedge(totNode, 1, k, 0);
printf("%d\n", SolveMinCost(totNode, n));
}