UVALive - 5095 Transportation(拆边+费用流)

题目大意:有n个点,m条边,每条边的容量为ci,费用为ai* x^2(x为流量,ai为所给系数)

现在问能否将k个单位的货物从点1运输到点n,且费用最小

解题思路:拆边,将每条边拆成ci条边,每条边的费用分别为ai * 1, ai * 3, ai * 5…容量都为1,在容量相同的情况下,会选择费用少的流,这样流过的边累加起来的费用刚好为 ai * 流量^2

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define N 1010
#define INF 0x3f3f3f3f

struct Edge{
    int from, to, cap, flow ,cost;
    Edge() {}
    Edge(int from, int to, int cap, int flow, int cost):from(from), to(to), cap(cap), flow(flow), cost(cost) {}
};

struct MCMF{
    int n, m, source, sink;
    int flow, cost;
    vector<Edge> edges;
    vector<int> G[N];
    int d[N], f[N], p[N];
    bool vis[N];

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

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

    bool BellmanFord(int s, int t, int &flow, int &cost, int need) {
        for (int i = 0; i <= n; i++)
            d[i] = INF;
        memset(vis, 0, sizeof(vis));
        vis[s] = 1; d[s] = 0; f[s] = need; p[s] = 0;
        queue<int> Q;
        Q.push(s);

        while (!Q.empty()) {
            int u = Q.front();
            Q.pop();
            vis[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.cost) {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    f[e.to] = min(f[u], e.cap - e.flow);
                    if (!vis[e.to]) {
                        vis[e.to] = true;
                        Q.push(e.to);
                    }
                }
            }
        }

        if (d[t] == INF)
            return false;

        flow += f[t];
        cost += d[t];

        int u = t;
        while (u != s) {
            edges[p[u]].flow += f[t];
            edges[p[u] ^ 1].flow -= f[t];
            u = edges[p[u]].from;
        }
        return true;
    }

    void Mincost(int s, int t, int need) {
        flow = 0, cost = 0;
        while (BellmanFord(s, t, flow, cost, need - flow)) {
            if (need == flow) break;
        }
    }
};
MCMF mcmf;
int n, m, k;
int num[6] = {0, 1, 3, 5, 7, 9};

void solve() {
    int u, v, a, c;
    mcmf.init(n);
    for (int i = 0; i < m; i++) {
        scanf("%d%d%d%d", &u, &v, &a, &c);
        for (int j = 1; j <= c; j++) mcmf.AddEdge(u, v, 1, num[j] * a);
    }

    mcmf.Mincost(1, n, k);
    if (mcmf.flow == k)
        printf("%d\n", mcmf.cost);
    else
        printf("-1\n");
}

int main() {
    while (scanf("%d%d%d", &n, &m, &k) != EOF) solve();
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-07 17:02:24

UVALive - 5095 Transportation(拆边+费用流)的相关文章

【 UVALive - 5095】Transportation(费用流)

Description There are N cities, and M directed roads connecting them. Now you want to transport K units ofgoods from city 1 to city N. There are many robbers on the road, so you must be very careful. Themore goods you carry, the more dangerous it is.

【BZOJ4930】棋盘 拆边费用流

[BZOJ4930]棋盘 Description 给定一个n×n的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置(x,y),(u,v)能互相攻击当前仅 当满足以下两个条件: 1:x=u或y=v 2:对于(x,y)与(u,v)之间的所有位置,均不是障碍. 现在有q个询问,每个询问给定ki,要求从棋盘中选出ki个空位置来放棋子,问最少互相能攻击到的棋子对数是多少? Input 第一行一个整数n. 接下来输入一个n×n的字符矩阵,一个位置若为.,则表示这是一个空位置,若为#,则为障碍. 第

【BZOJ2245】[SDOI2011]工作安排 拆边费用流

[BZOJ2245][SDOI2011]工作安排 Description 你的公司接到了一批订单.订单要求你的公司提供n类产品,产品被编号为1~n,其中第i类产品共需要Ci件.公司共有m名员工,员工被编号为1~m员工能够制造的产品种类有所区别.一件产品必须完整地由一名员工制造,不可以由某名员工制造一部分配件后,再转交给另外一名员工继续进行制造. 我们用一个由0和1组成的m*n的矩阵A来描述每名员工能够制造哪些产品.矩阵的行和列分别被编号为1~m和1~n,Ai,j为1表示员工i能够制造产品j,为0

【bzoj3442】学习小组 费用流

原文地址:http://www.cnblogs.com/GXZlegend/p/6809670.html 题目描述 [背景] 坑校准备鼓励学生参加学习小组. [描述] 共有n个学生,m个学习小组,每个学生有一定的喜好,只愿意参加其中的一些学习小组,但是校领导为学生考虑,规定一个学生最多参加k个学习小组.财务处的大叔就没那么好了,他想尽量多收钱,因为每个学生参加学习小组都要交一定的手续费,不同的学习小组有不同的手续费.然而,事与愿违,校领导又决定对学习小组组织者进行奖励,若有a个学生参加第i个学习

【bzoj2245】[SDOI2011]工作安排 费用流

题目描述 你的公司接到了一批订单.订单要求你的公司提供n类产品,产品被编号为1~n,其中第i类产品共需要Ci件.公司共有m名员工,员工被编号为1~m员工能够制造的产品种类有所区别.一件产品必须完整地由一名员工制造,不可以由某名员工制造一部分配件后,再转交给另外一名员工继续进行制造. 我们用一个由0和1组成的m*n的矩阵A来描述每名员工能够制造哪些产品.矩阵的行和列分别被编号为1~m和1~n,Ai,j为1表示员工i能够制造产品j,为0表示员工i不能制造产品j. 如果公司分配了过多工作给一名员工,这

hdu3667 Transportation 拆边法+最小费用最大流

/** 题目:hdu3667 Transportation 拆边法+最小费用最大流 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667 题意:n个城市由m条有向边连接.要从城市1运输k流量到城市n.每条边有可以运输的流量容量,以及费用系数ai. 费用系数指该条边的费用为该条边的运输流量x的平方乘以ai.即ai*x^2. 如果无法运输k流量,输出-1,否则输出从城市1运输k流量到城市n的最小花费. 思路:拆边法+最小费用最大流 假设从u->v 容量为

HDU 3667 Transportation(网络流之费用流)

题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k,需要让每一次增广到的流量都是1,这就需要把每一条边的流量都是1才行.但是每条边的流量并不是1,该怎么办呢.这个时候可以拆边,反正c最多只有5,拆成5条流量为1的边.但是这时候费用怎么办呢,毕竟平方的关系不能简单把每一条边加起来.这时候可以把拆的边的流量设为1,3,5,7,9.如果经过了3个流量,那就肯定会流1,3,5,费用为9,是3的平方,同理,其他的也是如此.然后按照给出的边建图跑一次费用流就可以了. 代码如下: #i

费用流 hdu3667 Transportation

传送门:点击打开链接 题意:n个节点m条有向边,每条有向边的容量是C,且费用是a*x^2,x是流量,问从1运送k流量到n的最小费用 一般做的费用流边的费用都是固定的,而这题并不是固定的. 但是,看到了C<=5,其实就是在提示可以拆边.. 假如C是3,我们就可以把一条边拆成3条边. 假如不拆,如果通过的流量是1,2,3,那么费用分别是a,4a,9a 如果拆成3条边,那么3条边的费用分别是a,3a,5a,容量都是1 这样就完美的解决了边的费用问题了~ #include<map> #inclu

【 UVALive - 2197】Paint the Roads(上下界费用流)

Description In a country there are n cities connected by m one way roads. You can paint any of these roads. To paint a road it costs d unit of money where d is the length of that road. Your task is to paint some of the roads so that the painted roads