题意:度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题:喵哈哈村以及周围的村庄可以看做是一共由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;
}