[題目]
給定一張有向圖,每條邊都有一個容量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));
}