您的位置:首页 > 其它

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

2017-08-21 22:04 405 查看

题目

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: