HDU 6118 度度熊的交易计划 最大费用最大流

题意:度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题:喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区。由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但是最多生产b[i]个。同样的,由于每个片区的购买能力的区别,第i个片区也能够以c[i]的价格出售最多d[i]个物品。由于这些因素,度度熊觉得只有合理的调动物品,才能获得最大的利益。据测算,每一个商品运输1公里,将会花费1元。那么喵哈哈村最多能够实现多少盈利呢?

题意目的:对于每一个村庄都可以进行买卖,每一个村庄都会赚到一部分钱,现在求所有村庄赚的钱最多为多少的问题。

思想:一个村庄,赚钱的方式是自己创造商品然后贩卖,中途路上的过路费自己掏(这个赚钱的方式和上述d[i]和c[i]有关),一个村庄的花费是生产的过程(这个过程与上述的a[i]和b[i]有关),天然会想到网络流。

  • 建立源点source、汇点sink,其中source和赚钱有关(d、c),sink和生产花钱有关(a、b)。
  • 从source指向村庄 i 建立一条流量为 d[i],费用为 c[i] 的边。
  • 从村庄 i 指向sink建立一条流量为 b[i],费用为 -a[i] 的边。
  • 对一条道路连接的两个村庄 i 和 j,因为是无向边,所以从 i 指向 j 连接一条容量为 INF,费用为 -w(道路的长度)的边,从 j 指向 i 连接一条容量为 INF,费用为 -w的边。
  • 从source到sink跑一遍最大费用最大流即可。

需要注意点一点就是,每次使用spfa增广之后,如果增广路的赚取的费用一旦小于0 即可退出网络流的增广过程,因为,dis的初始化是-INF,因为我要找的是最长增广,所以一点sink的 dis 小于零那就表示已经都是不赚钱的流通了,没有意义,继续下去还是赔钱。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 510;
const int INF = 0x7fffffff;

struct EDGE
{
	int u, v;
	int flow;
	int fee;
	EDGE(int u, int v, int flow, int fee): u(u), v(v), flow(flow), fee(fee){}
};

int n, m;
int source, sink;
bool vis[maxn];
int sb_node[maxn], sb_edge[maxn];
int dis[maxn];
vector<int>graph[maxn];
vector<EDGE>edge;

void init()
{
	source = 0;
	sink = n+1;
	for (int i = 0; i <= n+1; i++)
	{
		graph[i].clear();
	}
	edge.clear();
}

void add_edge(int u, int v, int flow, int fee)
{
	edge.push_back(EDGE(u, v, flow, fee));
	edge.push_back(EDGE(v, u, 0, -fee));
	int cnt = edge.size();
	graph[u].push_back(cnt-2);
	graph[v].push_back(cnt-1);
}

int Min(int x, int y)
{
	if (x < y) return x;
	else return y;
}

int dinic_spfa()
{
	queue<int>q;
	
	while (!q.empty()) q.pop();
	memset(vis, false, sizeof(vis));
	for (int i = source; i <= sink; i++)
	{
		dis[i] = -INF;
	}
	
	dis[source] = 0;
	vis[source] = true;
	q.push(source);
	int mark = 0;
	while (!q.empty())
	{
		
		int cur_node = q.front();
		q.pop();
		vis[cur_node] = false;
		for (int i = 0; i < graph[cur_node].size(); i++)
		{
			int id = graph[cur_node][i];
			int next_node = edge[id].v;
			int flow = edge[id].flow;
			int fee = edge[id].fee;
			if (dis[next_node] < dis[cur_node] + fee && flow > 0)
			{
				dis[next_node] = dis[cur_node] + fee;
				sb_node[next_node] = cur_node;
				sb_edge[next_node] = id;
				if (!vis[next_node])
				{
					vis[next_node] = true;
					q.push(next_node);
				}
			}
		}
	
	}
	return dis[sink];
}

int dinic()
{
	int tot_fee = 0;
	int cut_flow;
	int res;
	while (res = dinic_spfa())
	{
		if (res < 0)
		{
			break;
		}
		cut_flow = INF;
		for (int cur_node = sink; cur_node != source; cur_node = sb_node[cur_node])
		{
			int id = sb_edge[cur_node];
			cut_flow = Min(cut_flow, edge[id].flow);
		}
		tot_fee += cut_flow * res;
		for (int cur_node = sink; cur_node != source; cur_node = sb_node[cur_node])
		{
			int id = sb_edge[cur_node];
			edge[id].flow -= cut_flow;
			edge[id^1].flow += cut_flow;
		} 
	}
	return tot_fee;
}

int main()
{
	while (cin>> n>> m)
	{
		init();
		for (int i = 1; i <= n; i++)
		{
			int a, b, c, d;
			cin>> a>> b>> c>> d;
			add_edge(source, i, d, c);
			add_edge(i, sink, b, -a);
		}
		for (int i = 1; i <= m; i++)
		{
			int u, v, w;
			cin>> u>> v>> w;
			if (u == v) continue;
			add_edge(u, v, INF, -w);
			add_edge(v, u, INF, -w);
		}
		cout<< dinic()<< endl;
	}
	return 0;
}
发布了331 篇原创文章 · 获赞 135 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/Triple_WDF/article/details/103333790
今日推荐