种葱

题面描述

初音ミク的土地可以看成是由N个地块组成,由1到N编号,N个地块排成一横排。

鏡音リン提出了a个要求,要求从第l个到第r个地块(包括l和r),葱的总数不能超过v。

鏡音レン提出了b个要求,要求从第l个到第r个地块(包括l和r),葱的总数不能少于v。

同时,因为地块大小的限制,每个地块的葱不能超过k。

现在,初音ミク想知道,满足所有要求的情况下,她最多能种多少葱,最少能种多少葱。

输入格式

第一行两个整数N、k,用空格分开。

第二行一个整数a。

以后a行,每行三个整数l、r、v,用空格分开,意义如题目描述。

下一行一个整数b。

以后b行,每行三个整数l、r、v,用空格分开,意义如题目描述。

输出格式

第一行一个整数,表示葱的最大数目。

第二行一个整数,表示葱的最小数目。

样例

这个题我本来是,没有思路的,可是一看题解,我真的QAQ了,差分约束,我的天哪,我前一段时间刚刚搞过,现在碰到了还是不会,感觉白搞了QAQ,算了,先进入正题。此题他也给出了明确的约束条件,只不过我被区间迷惑了。并没有想到这是差分约束。对于每个i∈[0,N],建点i表示前i块地的葱的总数。对于每个i∈[1,N],建边(i-1,i,k)和(i,i-1,0);k是每块地所能种的最大葱树。对于每个要求[l,r]内的葱不超过v,建边(l-1,r,v);前缀和思想。对于每个要求[l,r]内的葱不少于v,建边(r,l-1,-v);建反向边,为了求最小值,这样就不用再新建一个图了,只是自己的理解。 (i,i-1,0) 和 (r,l-1,-v) 是用来求葱数最小用的,所以可以得出结论葱的最大值是从0到N的最短路。葱的最小值是从N到0的最短路的相反数。因为你设的是负边权,这也就是说明了用spfa。

代码

#include<bits/stdc++.h>
using namespace std;
const int oi=100010;
int ver1[oi],head1[oi],ne1[oi],edge1[oi],tot1=0,d1[oi],v1[oi];
int ver2[oi],head2[oi],ne2[oi],edge2[oi],d2[oi],v2[oi];
void add1(int x,int y,int z)
{
	ver1[++tot1]=y;
	edge1[tot1]=z;
	ne1[tot1]=head1[x];
	head1[x]=tot1;
} 
queue<int>q1;
void spfa1(int s)
{
	while(q1.size())
	q1.pop();
	memset(v1,0,sizeof(v1));
	memset(d1,10,sizeof(d1));
	v1[s]=1;
	q1.push(s);
	d1[s]=0;
	while(q1.size())
	{
		int now=q1.front();
		q1.pop();
		v1[now]=0;
		for(int i=head1[now];i;i=ne1[i])
		{
			if(d1[ver1[i]]>d1[now]+edge1[i])
			{
				d1[ver1[i]]=d1[now]+edge1[i];
				if(!v1[ver1[i]])
				{
					v1[ver1[i]]=1;
					q1.push(ver1[i]);
				}
			}
		}
	}
}
int main()
{
	int n,k,a,b;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		add1(i-1,i,k);
		add1(i,i-1,0);
	}
	cin>>a;
	for(int i=1;i<=a;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		add1(x-1,y,z);
	}
	cin>>b;
	for(int i=1;i<=b;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		add1(y,x-1,-z);
	}
	spfa1(0);
	cout<<d1[n]<<endl;
	spfa1(n);
	cout<<-d1[0]; 
}

留下评论

通过 WordPress.com 设计一个这样的站点
从这里开始