订货【费用流】

##题目大意:
有n个月,第i个月需要ui件货物,每个单位的货物再第i个月的价格是di,仓库容量为s,每放在仓库贮存1个月,每个单位的货物就要使用m元,若当月卖了出去则不用付.

##解题思路:
赤裸裸的费用流
其实网络流最重要的就是建图
图建好了套模版
下面是建图方式:
1.建立源点与每个月连接,流量为无穷大,费用为di.
2.建立汇点与每个月连接,流量为ui,费用为0.
3.第i个月与第i+1个月连接,流量为s,费用为m.
原因:
1.可以买进无数件,费用当然就是价格
2.最大流,这ui肯定要流的,然后费用在源点与每个月之间就已经"买单"了.
3.仓库容量是s,费用是m,然后货物可以给下个月用

##源程序:

#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
struct node{
	int x,to,f,c,next;
}e[205];
int d[55],pre[55],last[55],cnt=-1,ans,n,m,S,s,t;	
bool v[55];
void add(int u,int v,int c,int w)
{
	e[++cnt].x=u;e[cnt].to=v;e[cnt].f=w;e[cnt].c=c;e[cnt].next=last[u];last[u]=cnt;
	e[++cnt].x=v;e[cnt].to=u;e[cnt].f=-w;e[cnt].c=0;e[cnt].next=last[v];last[v]=cnt;
}
bool spfa()
{
	queue<int> q;
	for (int i=s;i<=t;i++) d[i]=1e9;
	memset(pre,-1,sizeof(pre));
	memset(v,0,sizeof(v));
	d[s]=0;q.push(s);v[s]=1;
	while(q.size())
	{
		int u=q.front();q.pop();v[u]=0;
		for (int i=last[u];~i;i=e[i].next)
		if (e[i].c&&d[e[i].to]>d[u]+e[i].f)
		{
			d[e[i].to]=d[u]+e[i].f;
			pre[e[i].to]=i;
			if (!v[e[i].to])
			{
				v[e[i].to]=1;
				q.push(e[i].to);
			}
		}	
		
	}
	return d[t]!=1e9;
}
void mcf()
{
	int i=t,minn=1e9;
	while (~pre[i])
	{
		minn=min(e[pre[i]].c,minn);
		i=e[pre[i]].x;
	}
	ans+=d[t]*minn; i=t;
	while (~pre[i])
	{
		e[pre[i]].c-=minn;
		e[pre[i]^1].c+=minn;
		i=e[pre[i]].x;
	}
	return;
}
int spf()
{
	while (spfa()) 
	 mcf();
	return ans;
}
//上面的都是模版
//我就不解释了
int main()
{
	memset(last,-1,sizeof(last));//初始化
	scanf("%d%d%d",&n,&m,&S);
	s=0;t=n+1;//建立源点汇点
	for (int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		add(i,t,x,0);//连接(每个月与汇点)
	}
	for (int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		add(s,i,1e9,x);//连接(源点与每个月)
	}
	for (int i=1;i<n;i++) add(i,i+1,S,m);//连接(每个月之间)
	//这里要i不能等于n,如果等于n,最后一个月就会和汇点再连一条线
	//就会改变整个费用流的结果
	printf("%d",spf());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值