2017百度之星初赛:B-1005. 度度熊的交易计划(最小费用流)

度度熊的交易计划

 
 Accepts: 460
 
 Submissions: 2329
 Time Limit: 12000/6000 MS (Java/Others)
 
 Memory Limit: 32768/32768 K (Java/Others)
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


小费用流

源点与所有点连接一条流量为最大生产数量b[i],费用为a[i]的边

所有点与汇点连接一条流量为最大出售量d[i],费用为-c[i]的边

然后如果点u和点v间有条长度为len的路径,则点u和点v连一条流量为inf,费用为len的边(注意是双向的)

这里别忘了去掉自环,重边保留最短

理论上之后求最小费用最大流就好了


但真的是最大流么?显然不一定

因为最大流也意味着所有点的商品都必须全部卖到最大出售量或者所有点的商品都买完最大生产量

这样显然是不对的,如果完全没法获得利润的话不如一个商品都不买

那怎么办

所有点与汇点再连接一条流量为最大生产数量b[i],费用为-a[i]的边就好了

这样子就相当于东西可以不买,再求的最小费用最大流就是答案了

直接套模板吧

#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long
#define inf 1044266558
typedef struct Res
{
	int next;
	int to, from;
	int flow, cost;
}Road;
Road G[2000005];
int head[505], vis[505], dis[505], road[505][505], S, T, cnt, ans; 
int a[505], b[505], c[505], d[505];
int Read()
{
	int x = 0, f = 1;
	char ch;
	ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')  f = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
		x = x*10+ch-'0', ch = getchar();
	return x*f;
}
void Add(int u, int v, int flow, int cost)
{
	cnt++;
	G[cnt].next = head[u];
	head[u] = cnt;
	G[cnt].from = u;
	G[cnt].to = v;
	G[cnt].flow = flow;
	G[cnt].cost = cost;
}
int SPFA()
{
	int now, i, v;
	queue<int> q;
	memset(vis, 0, sizeof(vis));
	memset(dis, 62, sizeof(dis));
	q.push(S);
	vis[S] = 1;
	dis[S] = 0;
	while(q.empty()==0)
	{
		now = q.front();
		q.pop();
		vis[now] = 0;
		for(i=head[now];i!=0;i=G[i].next)
		{
			v = G[i].to;
			if(G[i].flow && dis[v]>dis[now]+G[i].cost)
			{
				dis[v] = dis[now]+G[i].cost;
				if(vis[v]==0)
				{
					vis[v] = 1,
					q.push(v);
				}
			}
		}
	}
	if(dis[T]<inf)
		return 1;
	return 0;
}
int Sech(int now, int low)
{
	int i, w, used;
	vis[now] = 1;
	if(now==T)
		return low;
	used = low;
	for(i=head[now];i!=0;i=G[i].next)
	{
		if(G[i].flow && dis[G[i].to]==dis[now]+G[i].cost && vis[G[i].to]==0)
		{
			w = Sech(G[i].to, min(used, G[i].flow));
			G[i].flow -= w;
			G[i^1].flow += w;
			used -= w;
			ans += w*G[i].cost;
			if(used==0)
				return low;
		}
	}
	return low-used; 
}
int main(void)
{
	int i, j, n, m, u, v, len;
	while(scanf("%d%d", &n, &m)!=EOF)
	{
		cnt = 1;
		S = 0, T = n+1;
		memset(head, -1, sizeof(head));
		memset(road, 62, sizeof(road));
		ans = 0;
		for(i=1;i<=n;i++)
		{
			a[i] = Read(), b[i] = Read();
			c[i] = Read(), d[i] = Read();
		}
		for(i=1;i<=m;i++)
		{
			u = Read(), v = Read(), len = Read();
			if(u==v)
				continue;
			road[u][v] = road[v][u] = min(road[u][v], len);
		}
		for(i=1;i<=n;i++)
		{
			Add(S, i, b[i], a[i]);
			Add(i, S, 0, -a[i]);
			Add(i, T, d[i], -c[i]);
			Add(T, i, 0, c[i]);
			Add(i, T, b[i], -a[i]);
			Add(T, i, 0, a[i]);
		}
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				if(road[i][j]<=1000)
				{
					Add(i, j, inf, road[i][j]);
					Add(j, i, 0, -road[i][j]);
				}
			}
		}
		while(SPFA()) 
		{
			memset(vis, 0, sizeof(vis));
			while(Sech(S, inf))
				memset(vis, 0, sizeof(vis));
		}
		printf("%d\n", -ans);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值