【网络流】网络扩容
【问题描述】
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求:
1、 在不扩容的情况下,1到N的最大流;
2、 将1到N的最大流增加K所需的最小扩容费用。
【输入格式】network.in
输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。
接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
【输出格式】network.out
输出文件一行包含两个整数,分别表示问题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
这是一道最大流加最小费用流的问题。
最大流就不再多说了。
求出了最大流之后有个残量网络,将这些边的费用设为0(原图中剩余的流量免费),重新加入一些边(前提是原图中有这些边,于是),流量为k,费用为扩容费用,再加一个超级源,连一条容量为k,费用为0的边(限制流量最大为k),最后求一次最小费用流即可。
Accode:
#include
#include
#include
#include
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))const char fi[] = "network.in";
const char fo[] = "network.out";
const int maxN = 1010;
const int SIZE = 0x3ff;
const int MAX = 0x3f3f3f3f;
const int MIN = ~MAX;
struct Edge
{
int u, v, f, c;
Edge *next, *back;
};
Edge *edge[maxN];
Edge *pre[maxN];
bool mp[maxN][maxN];
int w[maxN][maxN];
int d[maxN];
int cnt[maxN];
int q[SIZE + 1];
int n, m, K, S = 1, T, f, r;
void init_file()
{
freopen(fi, "r", stdin);
freopen(fo, "w", stdout);
return;
}inline int getint()
{
int res = 0;
char tmp;
while (!isdigit(tmp = getchar()));
do res = (res << 3) + (res << 1) + tmp - '0';
while (isdigit(tmp = getchar()));
return res;
}inline void insert(int u, int v, int f, int c)
{
Edge *p = new Edge;
p -> u = u;
p -> v = v;
p -> f = f;
p -> c = c;
p -> next = edge[u];
edge[u] = p;
p = new Edge;
p -> u = v;
p -> v = u;
p -> f = 0;
p -> c = -c;
p -> next = edge[v];
edge[v] = p;
edge[u] -> back = edge[v];
edge[v] -> back = edge[u];
return;
}void readdata()
{
T = n = getint();
m = getint();
K = getint();
for (;
m;
--m)
{
int u = getint(), v = getint(),
f = getint(), c = getint();
mp[u][v] = 1;
//先用mp数组记录一下原图中有哪些边。
w[u][v] = w[u][v] ? min(w[u][v], c) : c;
//记录扩容费用。
insert(u, v, f, 0);
}
return;
}int Sap(int u, int Lim)
{
if (u == T) return Lim;
int tmp = 0;
for (Edge *p = edge[u];
p;
p = p -> next)
if (p -> f > 0 && d[u] == d[p -> v] + 1)
{
int k = Sap(p -> v, min(p -> f, Lim - tmp));
p -> f -= k;
p -> back -> f += k;
if ((tmp += k) == Lim) return tmp;
}
if (d[S] >= n) return tmp;
if ((--cnt[d[u]]) == 0) d[S] = n;
++cnt[++d[u]];
return tmp;
}int Spfa()
{
memset(pre, 0, sizeof pre);
memset(d, 0x3f, sizeof d);
memset(cnt, 0, sizeof cnt);
f = r = 0;
d[S] = 0;
++cnt[q[r++] = S];
r &= SIZE;
while (f != r)
{
int u = q[f++];
f &= SIZE;
--cnt[u];
for (Edge *p = edge[u];
p;
p = p -> next)
if (p -> f > 0)
{
int v = p -> v;
int c = p -> c;
if (d[u] + c < d[v])
{
d[v] = d[u] + c;
pre[v] = p;
if (!cnt[v])
{
++cnt[q[r++] = v];
r &= SIZE;
}
}
}
}
return pre[T] != NULL;
}int min_fee()
{
int ans = 0;
while (Spfa())
{
int max_flow = MAX;
for (Edge *p = pre[T];
p;
p = pre[p -> u])
max_flow = min(max_flow, p -> f);
for (Edge *p = pre[T];
p;
p = pre[p -> u])
{
p -> f -= max_flow;
p -> back -> f += max_flow;
}
ans += d[T] * max_flow;
}
return ans;
}void work()
{
int ans = 0;
cnt[0] = n;
while (d[S] < n) ans += Sap(S, MAX);
for (int u = 1;
u < n + 1;
++u)
for (int v = 1;
v < n + 1;
++v)
if (mp[u][v]) insert(u, v, MAX, w[u][v]);
insert(S = 0, 1, K, 0);
printf("%d %d\n", ans, min_fee());
return;
}int main()
{
init_file();
readdata();
work();
return 0;
}#undef min
#undef max
再贴一个求费用流时没有退流的骗分程序,能过90分。
#include
#include
#include
#include
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))const char fi[] = "network.in";
const char fo[] = "network.out";
const int maxN = 1010;
const int SIZE = 0x3ff;
const int MAX = 0x3f3f3f3f;
const int MIN = ~MAX;
struct Edge
{
int u, v, f, c;
Edge *next, *back;
};
Edge *edge[maxN];
int d[maxN];
int cnt[maxN];
int q[SIZE + 1];
int n, m, K, S = 1, T, f, r;
void init_file()
{
freopen(fi, "r", stdin);
freopen(fo, "w", stdout);
return;
}inline int getint()
{
int res = 0;
char tmp;
while (!isdigit(tmp = getchar()));
do res = (res << 3) + (res << 1) + tmp - '0';
while (isdigit(tmp = getchar()));
return res;
}inline void insert(int u, int v, int f, int c)
{
for (Edge *p = edge[u];
p;
p = p -> next)
if (p -> v == v)
{
p -> f += f;
p -> c = min(p -> c, c);
return;
}
Edge *p = new Edge;
p -> u = u;
p -> v = v;
p -> f = f;
p -> c = c;
p -> next = edge[u];
edge[u] = p;
p = new Edge;
p -> u = v;
p -> v = u;
p -> f = 0;
p -> c = MAX;
p -> next = edge[v];
edge[v] = p;
edge[u] -> back = edge[v];
edge[v] -> back = edge[u];
return;
}void readdata()
{
T = n = getint();
m = getint();
K = getint();
for (;
m;
--m)
{
int u = getint(), v = getint(),
f = getint(), c = getint();
insert(u, v, f, c);
}
return;
}int Sap(int u, int Lim)
{
if (u == T) return Lim;
int tmp = 0;
for (Edge *p = edge[u];
p;
p = p -> next)
if (p -> f > 0 && d[u] == d[p -> v] + 1)
{
int k = Sap(p -> v, min(p -> f, Lim - tmp));
p -> f -= k;
p -> back -> f += k;
if ((tmp += k) == Lim) return tmp;
}
if (d[S] >= n) return tmp;
if ((--cnt[d[u]]) == 0) d[S] = n;
++cnt[++d[u]];
return tmp;
}int Spfa()
{
memset(d, 0x3f, sizeof d);
memset(cnt, 0, sizeof cnt);
d[S] = 0;
++cnt[q[r++] = S];
r &= SIZE;
while (f != r)
{
int u = q[f++];
f &= SIZE;
--cnt[u];
for (Edge *p = edge[u];
p;
p = p -> next)
if (p -> c < MAX)
{
int v = p -> v;
int c = (p -> c) * max(0, K - p -> f);
if (d[u] + c < d[v])
{
d[v] = d[u] + c;
if (!cnt[v])
{
++cnt[q[r++] = v];
r &= SIZE;
}
}
}
}
return d[T];
}void work()
{
int ans = 0;
cnt[0] = n;
while (d[S] < n) ans += Sap(S, MAX);
printf("%d %d\n", ans, K ? Spfa() : 0);
return;
}int main()
{
init_file();
readdata();
work();
return 0;
}#undef min
#undef max
【【网络流】网络扩容】
推荐阅读
- 宽容谁
- 我要做大厨
- parallels|parallels desktop 解决网络初始化失败问题
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 猎杀IP
- 叙述作文