您的位置:首页 > 其它

【拆边最小费用流】【Asia - Harbin - 2010/2011】【Transportation】

2012-12-31 12:05 288 查看
【题目描述】There are N cities, and M directed roads connecting them. Now you want to transport K units of goods from city 1 to city N. There are many robbers on the road, so you must be very careful. The more goods you carry, the more dangerous it is. To be more specific, for each road i, there is a coefficient ai. If you want to carry x units of goods along this road, you should pay ai * x2 dollars to hire guards to protect your goods. And what's worse, for each road i, there is an upper bound Ci, which means that you cannot transport more than Ci units of goods along this road. Please note you can only carry integral unit of goods along each road.

You should find out the minimum cost to transport all the goods safely.

There are several test cases. The first line of each case contains three integers, N, M and K. (1

N

100, 1

M

5000, 0

K

100). Then M lines followed, each contains four integers (ui, vi, ai, Ci), indicating there is a directed road from city ui to vi, whose coefficient is ai and upper bound is Ci. (1

ui, vi

N, 0 < ai

100, Ci

5)

Output one line for each test case, indicating the minimum cost. If it is impossible to transport all the K units of goods, output `-1'.

Sample Input

2 1 2
1 2 1 2
2 1 2
1 2 1 1
2 2 2
1 2 1 2
1 2 2 2


Sample Output

4
-1
3


【中文大意】N个点M条有向边的图,希望从点1运送K单位货物到点N,每条边有运送货物的容量,以及运送货物的费用。值得小心的是,费用的计算方式改变了,不再是流量*费用,而是流量^2*费用。

【题目分析】由于费用的计算方式改变了,变成流量^2*费用,因此倘若仍按最小费用流的SPFA增广,就会发现某条费用小的边因为流量增广的比较多,而导致总费用不如分流到其它费用稍大的边上面。

      注意一个至关重要的条件,Ci<=5,上述情况的本质问题在于费用随流量呈二次方增长,如:当流量为1的时候,费用小的边必然先通过,但是当流量为增至2时候,这条边本质等于是2条流量为1的边,费用分别为1和3,这样也就能很明显的看出,拆边之后SPFA增广就可以进行了。

      想到将某条边的容量全部拆成容量为1的边,费用为1,3,5,7,9(最多为9),剩下的是跑最小费用流。可以增加一个点作为源点S,然后S->1连一条费用为0容量为K的边。顺便记录一下最大流的值,最后判断最大流是否等于K,是则输出最小费用,否则输出-1。

【代码如下】

#include <iostream>
#include <cstdio>
#include <climits>
#include <vector>
#include <deque>
#include <algorithm>

#define FILE_IO

using namespace std;

const int Maxn = 101, INF = INT_MAX;

struct edge
{
int v, c, w;
edge* next, * op;
edge(int _v, int _c, int _w, edge* _next) : v(_v), c(_c), w(_w), next(_next) {}
}* E[Maxn], * PE[Maxn];

bool hash[Maxn];
int S, T, Maxflow, Costflow, P[Maxn], N, M, K;
vector <int> Dist;
deque <int> Q;

void Clear()
{
for (int i = 0; i <= T; i ++)
{
E[i] = NULL; PE[i] = NULL; P[i] = 0;
}
}

void Augment()
{
int add = INF;
for (int i = T; i != S; i = P[i])
{
add = min(add, PE[i] -> c);
}
Maxflow += add;
for (int i = T; i != S; i = P[i])
{
PE[i] -> c -= add;
PE[i] -> op -> c += add;
Costflow += add * add * PE[i] -> w;
}
}

bool Label()
{
Dist.assign(T + 1, INF); Dist[S] = 0;
Q.push_back(S);
while (Q.size())
{
int i = Q.front(); Q.pop_front(); hash[i] = false;
for (edge* j = E[i]; j; j = j -> next)
{
int v = j -> v;
if (j -> c && Dist[i] + j -> w < Dist[v])
{
Dist[v] = Dist[i] + j -> w;
P[v] = i; PE[v] = j;
if (!hash[v])
{
hash[v] = true;
Q.push_back(v);
}
}
}
}
return Dist[T] != INF;
}

void SPFAFlow()
{
Maxflow = Costflow = 0;
while (Label()) Augment();
}

inline void edgeAdd(int x, int y, int c, int w)
{
E[x] = new edge(y, c, w, E[x]);
E[y] = new edge(x, 0, -w, E[y]);
E[x] -> op = E[y]; E[y] -> op = E[x];
}

void Init()
{
S = 0; T = N;
for (int i = 1; i <= M; i ++)
{
int x, y, c, w; cin >> x >> y >> w >> c;
for (int j = 1; j <= c; j ++) edgeAdd(x, y, 1, w * (j * 2 - 1));
}
edgeAdd(0, 1, K, 0);
}

int main()
{
#ifdef FILE_IO
//freopen("test.in", "r", stdin);
#endif // FILE_IO
while (cin >> N >> M >> K)
{
Init();
SPFAFlow();
if (Maxflow == K) cout << Costflow << endl;
else cout << -1 << endl;
Clear();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: