度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题:
喵哈哈村以及周围的村庄可以看做是一共由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
思路:最短路小于0是才跑流量,大于等于0时结束。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int a,b,c,d,n,m,u,v,w,s,t,num,N;
struct edge
{
int next,to,cap,flow,cost;
}e[6100];//500*2*2+1000*2*2
int head[505],pre[505],dis[505],vis[505];
void add(int from,int to,int cap,int cost)
{//拆点 反向弧
e[num].next=head[from];
e[num].to=to;
e[num].cap=cap;
e[num].flow=0;
e[num].cost=cost;
head[from]=num++;
e[num].next=head[to];
e[num].to=from;
e[num].cap=0;
e[num].flow=0;
e[num].cost=-cost;
head[to]=num++;
}
int spfa(int s,int t)
{
queue<int> q;
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));//注意
//每个点的前一条边的编号
vis[s]=1;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int now=q.front();
q.pop();
vis[now]=0;
for(int i=head[now];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(e[i].cap>e[i].flow&&dis[v]>dis[now]+e[i].cost)
{
dis[v]=dis[now]+e[i].cost;
pre[v]=i;//边的编号
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return pre[t]!=-1;
}
int MCMF()//逆向更新
{
int res=0;
while(spfa(s,t))
{//i是边的编号
int mi=inf;//取得最小值
for(int i=pre[t];i!=-1;i=pre[e[i^1].to])
{
if(mi>e[i].cap-e[i].flow)//容量流量之差
{
mi=e[i].cap-e[i].flow;
}
}
//i是前一条边
for(int i=pre[t];i!=-1;i=pre[e[i^1].to])
{
e[i].flow+=mi;//逆向加
e[i^1].flow-=mi;//正向减 负负得正
}
if(dis[t]>=0)
return res;
res+=dis[t]*mi;//dis[t]费用,mi流量
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
while(cin >> n >> m)
{
s=0,t=n+1;
N=n+2;
memset(head,-1,sizeof(head));
num=0;
for(int i=1;i<=n;i++)
{
cin >> a >> b >> c >> d;
add(s,i,b,a);//超级源点
add(i,t,d,-c);//超级汇点
}
while(m--)
{
cin >> u >> v >> w;
add(u,v,inf,w);
add(v,u,inf,w);//无向边
}
cout << -MCMF() << endl;
}
return 0;
}