bzoj 1061

1061: [Noi2008]志愿者招募

Description

  申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难
题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要
Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用
是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这
并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。

Input

  第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负
整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了
方便起见,我们可以认为每类志愿者的数量都是无限多的。

Output

  仅包含一个整数,表示你所设计的最优方案的总费用。

Sample Input

3 3
2 3 4
1 2 2
2 3 5
3 3 2

Sample Output

14

HINT

1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。


确实,只有这里有比较详细的解释了
蒟蒻的网络流很垃圾。。于是看了好一会


因为我们知道网络流肯定都是流量平衡的,所以只要最大流量了,那么肯定就能满足所有的等式------也就是能把所有的常数项满足,就满足条件了
但似乎题目也没有无解的数据,要不他的答案就错了(反正无解也没有答案)
贴一下代码 (很多都是抄的):
#include<cstdio>
#include<cstring>
const int N=1005;
const int MAX=1<<30;
int n,m;
int st1,ed1;
struct qq
{
	int x,y;
	int last;
	int z,z1,other;
}s[50005];
int num,last[N];
int ans=0;
int init1 (int x,int y,int z,int z1)
{
	num++;
	s[num].x=x;s[num].y=y;s[num].z=z;s[num].z1=z1;
	s[num].last=last[x];
	last[x]=num;
	return num;
}
void init (int x,int y,int z,int z1)
{
	int num1=init1(x,y,z,z1),num2=init1(y,x,0,-z1);
	s[num1].other=num2;s[num2].other=num1;
	return ;
}
int dis[N],from[N],q[N];
bool q1[N];
bool SPFA ()
{
	memset(dis,127,sizeof(dis));
	memset(from,-1,sizeof(from));
	memset(q1,false,sizeof(q1));
	int st=1,ed=2;
	dis[st1]=0;from[st1]=-1;q1[st1]=true;q[st]=st1;
	while (st!=ed)
	{
		int x=q[st];
		for (int u=last[x];u!=-1;u=s[u].last)
		{
			int y=s[u].y;
			if (s[u].z>0&&dis[x]+s[u].z1<dis[y])
			{
				from[y]=u;
				dis[y]=dis[x]+s[u].z1;
				if (q1[y]==false)
				{
					q1[y]=true;
					q[ed]=y;
					ed++;
					if (ed>=N-1) ed=1;
				}
			}
		}
		q1[x]=false;
		st++;
		if (st>=N-1) st=1;
	}
	if (from[ed1]!=-1) return true;
	return false;
}
int mymin (int x,int y)
{
	return x<y?x:y;
}
void add ()
{
	int x=from[ed1];
	int f=MAX;
	while (x!=-1)
	{
		f=mymin(f,s[x].z);
		x=from[s[x].x];
	}
	x=from[ed1];
	while (x!=-1)
	{
		ans=ans+f*s[x].z1;
		s[x].z-=f;
		s[s[x].other].z+=f;
		x=from[s[x].x];
	}
}
int main()
{
	num=0;memset(last,-1,sizeof(last));
	st1=1003;ed1=st1+1;
	int l=0;
	scanf("%d%d",&n,&m);
	for (int u=1;u<=n;u++)
	{
		int x,a;
		scanf("%d",&a);
		x=a-l;l=a;
		if (x>0) init(st1,u,x,0);
		else init(u,ed1,-x,0);//常数 
		init(u+1,u,MAX,0);//Y值
	}
	init(n+1,ed1,l,0);
	for (int u=1;u<=m;u++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		init(x,y+1,MAX,z);//X值
	}
	while (SPFA()==true) add();
	printf("%d\n",ans);
	return 0;
}
做完这题,我知道了:可以根据流量平衡来进行网络流的建图,以后还有多多练习网络流
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值