题意
某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,如果上个月没有卖完的货会存到仓库里,储存费用要m,仓库容量为s。假定第一月月初的库存量为零,第n月月底的库存量也为零。计算如何安排订购计划可以使得成本最低。
思路
我们把进货的地方设为源点,销售出去的地方设为汇点。那么源点到每个月的点的边上容量为无限,费用为进货价;每个月的点到汇点的边上容量为需求量,费用为0;每个月之间的边的容量为仓库的容量,费用为储存的费用。然后跑一边费用流就能求出答案了。
代码
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int tot,n,m,s,u,head[53],S,T,ans,pre[53],d[53],v[53];
struct node{
int x,y,next,flow,cost;
}e[151];
void add(int x,int y,int l,int f)
{
e[++tot].x=x;
e[tot].y=y;
e[tot].cost=f;
e[tot].flow=l;
e[tot].next=head[x];
head[x]=tot;
e[++tot].x=y;
e[tot].y=x;
e[tot].cost=-f;
e[tot].flow=0;
e[tot].next=head[y];
head[y]=tot;
}
bool spfa()
{
queue<int> q;
int x,y;
for (int i=S;i<=T;i++)
{
d[i]=2147483647;
v[i]=0;
}
q.push(S);v[S]=1;d[S]=0;
while (q.size())
{
x=q.front();q.pop();v[x]=0;
for (int i=head[x];~i;i=e[i].next)
{
if (!e[i].flow) continue;
y=e[i].y;
if (d[y]>d[x]+e[i].cost)
{
d[y]=d[x]+e[i].cost;
pre[y]=i;
if (!v[y])
{
v[y]=1;
q.push(y);
}
}
}
}
return d[T]<2147483647;
}
void addflow()
{
int i=T,mn=2147483647;
while (pre[i])
{
mn=min(mn,e[pre[i]].flow);
i=e[pre[i]].x;
}
ans+=d[T]*mn;
i=T;
while (pre[i])
{
e[pre[i]].flow-=mn;
e[pre[i]^1].flow+=mn;
i=e[pre[i]].x;
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
S=0;T=n+1;
tot=1;
memset(head,-1,sizeof(head));
for (int i=1;i<=n;i++)
{
scanf("%d",&u);
add(i,T,u,0);//因为T代表市场,所以容量就为市场的需求量
if (i>1) add(i-1,i,s,m);//每个月剩余的要存到仓库里
}
for (int i=1;i<=n;i++)
{
scanf("%d",&u);
add(S,i,2147483647,u);//可以一直从进货的地方进货
}
while (spfa()) addflow();
printf("%d",ans);
}