uva 1486 Transportation (费用流+拆边)

uva 1486 Transportation

Description

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.

Input

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

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( n<=100 )座城市,由m( m<=5000 )条单向道路相连。你希望从城市1运送k( k<=100 )单位货物到城市n,这些道路并不安全,有很多强盗,所以你需要雇佣镖师来做护卫。每条道路都有一个危险系数ai( ai<=100 ),如果你带着x个单位的货物通过,需要给镖师 aix2 的佣金,镖师才会保证你的安全。每条道路都有一个限制,最多能运送Ci( Ci<=5 )的货物。现在问,在能完成运送x个单位的货物到n号城市的情况下最小的花费,如果送不到,则输出-1。
解题思路:如果不进行拆边的话,每条道路的费用是动态变化的,所以我们要进行拆边,使得每条道路的费用固定。假如一条边的危险系数是a,最多能运送的货物为C,那么这条边就可以C条边每条边的费用为 a(i2(i1)2) ,i从1到C,容量为1。这样拆出来的边总费用为 aC2 ,总容量为C。拆完边,建完图,跑一发最小费。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 200;
const int M = 150000;
typedef long long ll;
int n, m, k, s, t;
int pre[N], inq[N]; 
ll a[N], d[N];
struct Edge{
    int from, to;
    ll cap, flow;
    ll cos;
};

vector<Edge> edges;
vector<int> G[M];

void init() {
    for (int i = 0; i < M; i++) G[i].clear();
    edges.clear();
}

void addEdge(int from, int to, ll cap, ll flow, ll cos) {
    edges.push_back((Edge){from, to, cap, 0, cos});
    edges.push_back((Edge){to, from, 0, 0, -cos});
    int m = edges.size();
    G[from].push_back(m - 2); G[to].push_back(m - 1);
}

int BF(int s, int t, ll& flow, ll& cost) {
    queue<int> Q;
    memset(inq, 0, sizeof(inq));
    memset(a, 0, sizeof(a));
    memset(pre, 0, sizeof(pre));
    for (int i = 0; i < N; i++) d[i] = INF;
    d[s] = 0;
    a[s] = INF;
    inq[s] = 1;
    int flag = 1;
    pre[s] = 0;
    Q.push(s);
    while (!Q.empty()) {
        int u = Q.front(); Q.pop();
        inq[u] = 0;
        for (int i = 0; i < G[u].size(); i++) {
            Edge &e = edges[G[u][i]];
            if (e.cap > e.flow && d[e.to] > d[u] + e.cos) {
                d[e.to] = d[u] + e.cos;
                a[e.to] = min(a[u], e.cap - e.flow);
                pre[e.to] = G[u][i];
                if (!inq[e.to]) {
                    inq[e.to] = 1;
                    Q.push(e.to);
                }
            }   
        }
        flag = 0;
    }
    if (d[t] == INF) return 0;
    flow += a[t];
    cost += (ll)d[t] * (ll)a[t];
    for (int u = t; u != s; u = edges[pre[u]].from) {
        edges[pre[u]].flow += a[t];
        edges[pre[u]^1].flow -= a[t];
    }
    return 1;
}

int MCMF(int s, int t, ll& cost) {
    ll flow = 0;
    cost = 0;       
    while (BF(s, t, flow, cost));
    return flow;
}

void input() {
    int u, v;
    ll a;
    ll c;
    for (int i = 0; i < m; i++) {
        scanf("%d %d %lld %lld", &u, &v, &a, &c);
        for (int i = 1; i <= c; i++) {
            addEdge(u, v, 1, 0, a * (i * i - (i - 1) * (i - 1)));   
        }
    }
    addEdge(0, 1, k, 0, 0);
    s = 0, t = n;
}

int main() {
    while (scanf("%d %d %d", &n, &m, &k) == 3) {
        init();
        input();    
        ll cost;    
        if (MCMF(s, t, cost) != k) printf("-1\n");
        else printf("%lld\n", cost);
    }   
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值