问题描述:
W 公司有 m个仓库和 n 个零售商店。第 i 个仓库有 ai 个单位的货物;第 j 个零售商店需要 bj 个单位的货物。货物供需平衡,即∑ai = ∑bj。从第 i 个仓库运送每单位货物到第 j 个零售商店的费用为 cij 。试设计一个将仓库中所有货物运送到零售商店的运输方案,使总运输费用最少。
编程任务:
对于给定的 m 个仓库和 n 个零售商店间运送货物的费用,计算最优运输方案和最差运输方案。
输入数据:
由文件trans.in提供输入数据。文件的第1行有 2 个正整数m和 n,分别表示仓库数和零售商店数。接下来的一行中有m个正整数ai ,1≤i≤m,表示第 i个仓库有ai个单位的货物。再接下来的一行中有n个正整数 bj ,1≤j≤n,表示第j个零售商店需要 bj 个单位的货物。接下来的 m行,每行有n个整数,表示从第i个仓库运送每单位货物到第j个零售商店的费用 cij 。
输出结果:
程序运行结束时,将计算出的最少运输费用和最多运输费用输出到文件trans.out中。
样例输入:
2 3
220 280
170 120 210
77 39 105
150 186 122
样例输出:
48500
69140
這是一道最小費用流。方法類似於Going Home,也可用KM算法解決。
Accode:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>
#include <queue>
using std::queue;
using std::bitset;
const char fi[] = "trans.in";
const char fo[] = "trans.out";
const int maxN = 10010;
const int MAX = 0x3f3f3f3f;
const int MIN = ~MAX;
struct Edge
{
int u, v, f_min, f_max, d;
Edge *next, *back;
};
Edge *edge[maxN];
Edge *pre[maxN];
int dist[maxN];
queue <int> q;
bitset <maxN> marked;
int n, m, S, T, Min, Max;
void init_file()
{
freopen(fi, "r", stdin);
freopen(fo, "w", stdout);
}
inline void insert(int u, int v, int f, int d)
{
Edge *p = new Edge;
p -> u = u;
p -> v = v;
p -> f_min = p -> f_max = f;
p -> d = d;
p -> next = edge[u];
edge[u] = p;
p = new Edge;
p -> u = v;
p -> v = u;
p -> f_min = p -> f_max = 0;
p -> d = -d;
p -> next = edge[v];
edge[v] = p;
edge[u] -> back = edge[v];
edge[v] -> back = edge[u];
}
void readdata()
{
scanf("%d%d", &n, &m);
S = n + m + 1;
T = n + m + 2;
int c;
for (int i = 1; i < n + 1; ++i)
{
scanf("%d", &c);
insert(S, i, c, 0);
}
for (int j = 1; j < m + 1; ++j)
{
scanf("%d", &c);
insert(j + n, T, c, 0);
}
for (int i = 1; i < n + 1; ++i)
for (int j = 1; j < m + 1; ++j)
{
scanf("%d", &c);
insert(i, j + n, MAX, c);
}
}
bool Spfa_min()
{
while (!q.empty()) q.pop();
memset(dist, 0x3f, sizeof(dist));
memset(pre, 0, sizeof(pre));
q.push(S);
dist[S] = 0;
marked.set(S);
while (!q.empty())
{
int u = q.front();
q.pop();
marked.reset(u);
for (Edge *p = edge[u]; p; p = p -> next)
if (p -> f_min > 0 && dist[u]
+ p -> d < dist[p -> v])
{
dist[p -> v] = dist[u] + p -> d;
pre[p -> v] = p;
if (!marked.test(p -> v))
{
q.push(p -> v);
marked.set(p -> v);
}
}
}
return pre[T];
}
bool Spfa_max()
{
while (!q.empty()) q.pop();
memset(dist, 0xc0, sizeof(dist));
memset(pre, 0, sizeof(pre));
q.push(S);
dist[S] = 0;
marked.set(S);
while (!q.empty())
{
int u = q.front();
q.pop();
marked.reset(u);
for (Edge *p = edge[u]; p; p = p -> next)
if (p -> f_max > 0 && dist[u]
+ p -> d > dist[p -> v])
{
dist[p -> v] = dist[u] + p -> d;
pre[p -> v] = p;
if (!marked.test(p -> v))
{
q.push(p -> v);
marked.set(p -> v);
}
}
}
return pre[T];
}
void work()
{
while (Spfa_min())
{
int max_flow = MAX;
for (Edge *p = pre[T]; p; p = pre[p -> u])
max_flow = std::min(max_flow, p -> f_min);
for (Edge *p = pre[T]; p; p = pre[p -> u])
{
p -> f_min -= max_flow;
p -> back -> f_min += max_flow;
}
Min += max_flow * dist[T];
}
while (Spfa_max())
{
int max_flow = MAX;
for (Edge *p = pre[T]; p; p = pre[p -> u])
max_flow = std::min(max_flow, p -> f_max);
for (Edge *p = pre[T]; p; p = pre[p -> u])
{
p -> f_max -= max_flow;
p -> back -> f_max += max_flow;
}
Max += max_flow * dist[T];
}
printf("%d\n%d", Min, Max);
}
int main()
{
init_file();
readdata();
work();
exit(0);
}
第二次做:
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
const int maxN = 1010, SIZE = 0xfff;
const int MAX = 0x3f3f3f3f, MIN = ~MAX;
struct Edge
{int u, v, f_min, f_max, d; Edge *next, *back;};
Edge *edge[maxN], *pre[maxN];
bool marked[maxN];
int dist[maxN], q[SIZE + 1], n, m, S, T, f, r;
inline void Ins(int u, int v, int f, int d)
{
Edge *p = new Edge;
p -> u = u; p -> v = v; p -> d = d;
p -> f_min = p -> f_max = f;
p -> next = edge[u]; edge[u] = p;
p = new Edge;
p -> u = v; p -> v = u; p -> d = -d;
p -> f_min = p -> f_max = 0;
p -> next = edge[v]; edge[v] = p;
edge[u] -> back = edge[v];
edge[v] -> back = edge[u];
return;
}
inline int min(int a, int b) {return a < b ? a : b;}
inline int max(int a, int b) {return a > b ? a : b;}
inline bool Spfa(int (*opt)(int, int))
{
memset(dist, opt(0, 1) ? (~0x3f) : 0x3f, sizeof dist);
memset(pre, 0, sizeof pre);
memset(marked, 0, sizeof marked);
dist[S] = 0; f = r = 0;
marked[q[r++] = S] = 1; r &= SIZE;
while (f - r)
{
int u = q[f++]; f &= SIZE; marked[u] = 0;
for (Edge *p = edge[u]; p; p = p -> next)
if ((opt(0, 1) ? p -> f_max : p -> f_min) > 0)
{
int v = p -> v, tmp = opt(dist[v], dist[u] + p -> d);
if (tmp - dist[v])
{
dist[v] = tmp; pre[v] = p;
if (!marked[v]) {marked[q[r++] = v] = 1; r &= SIZE;}
}
}
}
return (bool)pre[T];
}
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;
}
int main()
{
freopen("trans.in", "r", stdin);
freopen("trans.out", "w", stdout);
n = getint(); m = getint();
S = n + m + 1; T = n + m + 2;
for (int i = 1; i < n + 1; ++i)
Ins(S, i, getint(), 0);
for (int j = 1; j < m + 1; ++j)
Ins(j + n, T, getint(), 0);
for (int i = 1; i < n + 1; ++i)
for (int j = 1; j < m + 1; ++j)
Ins(i, j + n, MAX, getint());
int Min = 0, Max = 0;
while (Spfa(min))
{
int Max_flow = MAX;
for (Edge *p = pre[T]; p; p = pre[p -> u])
Max_flow = min(Max_flow, p -> f_min);
for (Edge *p = pre[T]; p; p = pre[p -> u])
{
p -> f_min -= Max_flow;
p -> back -> f_min += Max_flow;
}
Min += Max_flow * dist[T];
}
while (Spfa(max))
{
int Max_flow = MAX;
for (Edge *p = pre[T]; p; p = pre[p -> u])
Max_flow = min(Max_flow, p -> f_max);
for (Edge *p = pre[T]; p; p = pre[p -> u])
{
p -> f_max -= Max_flow;
p -> back -> f_max += Max_flow;
}
Max += Max_flow * dist[T];
}
printf("%d\n%d\n", Min, Max);
return 0;
}