【SDOJ 2726】食堂

【题目】

题目描述:

在 SD 食堂,所有的座位是一行一行的排列。现在有 N 个座位排成一行,依次编号 1,2,…,N,每个座位只能坐一个人,现在L想数一下有多少个人坐着,一个一个数太慢了,L 决定只选择 M 段连续的座位,对每段分别数出人数。由于食堂噪音十分嘈杂, L 无法专心,可能有数错了。但是 L 认为没有数漏,最多是重复计数导致的。现在他把得到的数据给你,希望你帮他算出,一共最多有多少人。

输入格式:

第一行 2 个整数 N,M,分别是座位数量,和 L 分成 M 段

接下来M行,每行3个整数,l,r,k,表示 L 数了 l 到 r 这一段的座位,他数出的人数是 k

输出格式:

数出一行一个整数表示答案

样例数据:

输入
4 2
1 2 1 
2 4 2

输出
3

备注:

数据规模与约定:
20% 数据,N,M ≤ 20
40% 数据,N,M ≤ 500
20% 数据,L选的每段座位不相交
100% 数据,1 ≤ N,M,K ≤ 100000,1 ≤ l ≤ r ≤ N

【分析】

又是一道我连20分都没有的题

dzy大佬说这是一道裸的差分约束的题,然后。。。

好吧还是差分约束不熟悉,只打过模板,没怎么练题

emmm话不多说我们来讲一下正解

有一个坑点就是不止 L 数的区间内有人,不在任意一个区间内的位置依旧可以坐人,为了答案最大这些地方应坐满人

由于是区间操作,我们用前缀和,即用 sum[ i ] 表示 i 号位置及前面的人的数量

首先对于所有的 i,都有 sum[ i ] - sum[ i - 1 ] ≥ 0,转换成 sum[ i - 1 ] - sum[ i ] ≤ 0

还有就是 sum[ i ] - sum[ i - 1 ] ≤ 1,就是每个位置最多坐一个人

然后约束就是,sum[ r ] - sum[ l ] ≤ k

按照这样建边然后跑SPFA就可以了

【代码】

为了代码简洁我把读优删了,不加读优好像是要 T 的

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2000005
#define oo 2e+9
using namespace std;
int n,m,t;
int v[N],w[N],next[N];
int d[N],q[N],first[N],sum[N];
bool vis[N];
void add(int x,int y,int z)
{
	t++;
	next[t]=first[x];
	first[x]=t;
	v[t]=y;
	w[t]=z;
}
void spfa(int s)
{
	int x,y,i,j,end=1;
	for(i=1;i<=n;++i)
	{
		d[i]=oo;
		vis[i]=false;
	}
	q[1]=s;
	d[s]=0;
	vis[s]=true;
	for(j=1;j<=end;++j)
	{
		x=q[j];
		vis[x]=false;
		for(i=first[x];i;i=next[i])
		{
			y=v[i];
			if(d[y]>d[x]+w[i])
			{
				d[y]=d[x]+w[i];
				if(!vis[y])
				{
					q[++end]=y;
					vis[y]=true;
				}
			}
		}
	}
}
int main()
{
//	freopen("dining.in","r",stdin);
//	freopen("dining.out","w",stdout);
	int l,r,i,k;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	{
		add(i,i-1,0);
		add(i-1,i,1);
	}
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d",&l,&r,&k);
		add(l-1,r,k);
	}
	spfa(0);
	printf("%d",d[n]);
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/81283947