HDU 3667-- Transportation【最小费最大流 && 拆边建图 && 经典】

44 篇文章 0 订阅

Transportation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2441    Accepted Submission(s): 1041


Problem 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 a i. If you want to carry x units of goods along this road, you should pay a i * x 2 dollars to hire guards to protect your goods. And what’s worse, for each road i, there is an upper bound C i, which means that you cannot transport more than C i 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 (u i, v i, a i, C i), indicating there is a directed road from city u i to v i, whose coefficient is a i and upper bound is C i. (1 <= u i, v i <= N, 0 < a i <= 100, C i <= 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个城市和M条单向路线。对于每条线路,有四个信息:起点a、终点b、费用系数c、容量d(1<=d<=5),表示(1) 运送x单位的货物需要花费c * x * x,(二) 这条路最多能运送d单位的货物。现在问你能否将K单位货物从1运送到N,若可以输出最小花费,否则输出-1。


解析:

这题一看就是用费用流来写,但是费用流的前提是费用和流量是成正比的,但这一题费用和流量的平方成正比。所以这里要转化一下,目的是要把c * x * x 变成 c * x1 + c* x2 + ...c * xi。即把每条边拆d条边,每条边的费用为 c * xi,容量为1。这里我们就要想办法表示出xi。

根据等差公式,我们知道,n * n = 1 + 3 + 5 + … +(2n - 1)。 这就是我们要表示的xi。

转化好以后就是裸的费用流的问题了。

不太理解的可以看看这篇文章,讲的比我仔细。点我


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define maxn 110
#define maxm 100000 + 10
#define INF 0x3f3f3f3f
using namespace std;
int n, m, k;
int inset, outset;

struct node {
    int u, v, cap, flow, cost, next;
};

node edge[maxm];
int head[maxn], cnt;
int dist[maxn], vis[maxn];
int per[maxn];

void init(){
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void add(int u, int v, int w, int c){
    edge[cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].cap = w;
    edge[cnt].flow = 0;
    edge[cnt].cost = c;
    edge[cnt].next = head[u];
    head[u] = cnt++;
    edge[cnt].u = v;
    edge[cnt].v = u;
    edge[cnt].cap = 0;
    edge[cnt].flow = 0;
    edge[cnt].cost = -c;
    edge[cnt].next = head[v];
    head[v] = cnt++;
}

void getmap(){
    int a, b, c, d;
    outset = 0;
    inset = n + 1;
    for(int i = 1;i <= m; ++i){
        scanf("%d%d%d%d", &a, &b, &c, &d);
        for(int j = 1; j <= d; ++j){
            add(a, b, 1, (j * 2 - 1)*c);
        }
    }
    add(outset, 1, k, 0);
    add(n, inset, k, 0);
}

bool SPFA(int st, int ed){
    queue<int>q;
    for(int i = 0; i <= inset; ++i){
        dist[i] = INF;
        vis[i] = 0;
        per[i] = -1;
    }
    dist[st] = 0;
    vis[st] = 1;
    q.push(st);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; i != -1; i = edge[i].next){
            node E = edge[i];
            if(dist[E.v] > dist[u] + E.cost && E.cap > E.flow){
                dist[E.v] = dist[u] + E.cost;
                per[E.v] = i;
                if(!vis[E.v]){
                    vis[E.v] = 1;
                    q.push(E.v);
                }
            }
        }
    }
    return per[ed] != -1;
}

void MCMF(int st, int ed, int &cost, int &flow){
    flow = 0;
    cost = 0;
    while(SPFA(st, ed)){
        int mins = INF;
        for(int i = per[ed]; i != -1; i = per[edge[i ^ 1].v]){
            mins = min(mins, edge[i].cap - edge[i].flow);
        }
        for(int i = per[ed]; i != -1; i = per[edge[i ^ 1].v]){
            edge[i].flow += mins;
            edge[i ^ 1].flow -= mins;
            cost += edge[i].cost * mins;
        }
        flow += mins;
    }
}

int main (){
    while(scanf("%d%d%d", &n, &m, &k) != EOF){
        init();
        getmap();
        int cost ,flow;
        MCMF(outset, inset, cost, flow);
        if(flow == k)
            printf("%d\n", cost);
        else
            printf("-1\n");
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值