度度熊的交易计划
Accepts: 460
Submissions: 2329
Time Limit: 12000/6000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
最小费用流
源点与所有点连接一条流量为最大生产数量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;
}