hdu 6118 度度熊的交易计划【费用流模板题】

题目

http://acm.hdu.edu.cn/showproblem.php?pid=6118

题意

Problem Description
度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题:

喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区。

由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但是最多生产b[i]个。

同样的,由于每个片区的购买能力的区别,第i个片区也能够以c[i]的价格出售最多d[i]个物品。

由于这些因素,度度熊觉得只有合理的调动物品,才能获得最大的利益。

据测算,每一个商品运输1公里,将会花费1元。

那么喵哈哈村最多能够实现多少盈利呢?

Input
本题包含若干组测试数据。 每组测试数据包含: 第一行两个整数n,m表示喵哈哈村由n个片区、m条街道。 接下来n行,每行四个整数a[i],b[i],c[i],d[i]表示的第i个地区,能够以a[i]的价格生产,最多生产b[i]个,以c[i]的价格出售,最多出售d[i]个。 接下来m行,每行三个整数,u[i],v[i],k[i],表示该条公路连接u[i],v[i]两个片区,距离为k[i]

可能存在重边,也可能存在自环。

满足: 1<=n<=500, 1<=m<=1000, 1<=a[i],b[i],c[i],d[i],k[i]<=1000, 1<=u[i],v[i]<=n

Output
输出最多能赚多少钱。

Sample Input
2 1
5 5 6 1
3 5 7 7
1 2 1
Sample Output
23

分析

二话不说,建图跑费用流
1:首先拆点,每个点拆成生产者和消费者,生产者和消费者之间连边,花费为0,容量为INF(自营自销)
2:增加超源超汇,超源点向生产者连有向边,边容量是最大产量,边花费是生产价值,消费者向超汇点连边,边容量是最大消耗量,边花费是售价的负值。
3:生产者向生产者连边,生产者向消费者连边,边容量都是INF,花费是边距。
注意:
图中有自环和重边。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cmath>
using namespace std;
const int maxn=2*500+10;
const int INF = 100000000;

typedef long long LL;

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

struct MCMF {
    int n, m, s, t;
    vector<Edge> edges;
    vector<int> G[maxn];
    int inq[maxn];         // 是否在队列中
    int d[maxn];           // Bellman-Ford
    int p[maxn];           // 上一条弧
    int a[maxn];           // 可改进量
    long long res;
    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, LL& ans) {
        for(int i = 0; i <= n; i++) d[i] = INF;
        memset(inq, 0, sizeof(inq));
        d[s] = 0;
        inq[s] = 1;
        p[s] = 0;
        a[s] = INF;

        queue<int> Q;
        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.cost) {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if(!inq[e.to]) {
                        Q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }
        if(d[t]>0)return false;
        ans += (LL)d[t] * (LL)a[t];
        res=min(ans,res);
        int u = t;
        while(u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
            u = edges[p[u]].from;
        }
        return true;
    }

    // 需要保证初始网络中没有负权圈
    LL Mincost(int s, int t) {
        res=0;
        LL cost = 0;
        while(BellmanFord(s, t, cost));
        return res;
    }

};


MCMF mf;
const int M=1009;
int u[M],v[M],k[M];
typedef pair<int,int> pii;
int main()
{
    int n,m,a,b,c,d;
    while(~scanf("%d%d",&n,&m)){
        int S=0,T=2*n+1;
        mf.init(T);
        map<pii,int>mp;
        for(int i=1;i<=n;i++){
            scanf("%d%d%d%d",&a,&b,&c,&d);
            mf.AddEdge(S,i,b,a);
            mf.AddEdge(n+i,T,d,-c);
            mf.AddEdge(i,n+i,INF,0);
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u[i],&v[i],&k[i]);
            if(u[i]>v[i])swap(u[i],v[i]);
            pii uv=pii(u[i],v[i]);
            if(mp.count(uv))mp[uv]=min(mp[uv],k[i]);
            else mp[uv]=k[i];
        }
        for(int i=1;i<=m;i++){
            if(u[i]==v[i])continue;
            if(mp[pii(u[i],v[i])]!=k[i])continue;
            mp[pii(u[i],v[i])]=0;
            mf.AddEdge(u[i],v[i]+n,INF,k[i]);
            mf.AddEdge(u[i],v[i],INF,k[i]);
            mf.AddEdge(v[i],u[i],INF,k[i]);
            mf.AddEdge(v[i],u[i]+n,INF,k[i]);
        }
        long long ans=0;
        ans=mf.Mincost(S,T);
        if(ans>0)ans=0;
        cout<<abs(ans)<<endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值