POJ - 2373(线段树+DP)

解决如何用最少数量的喷灌器覆盖所有奶牛喜好的草区,喷灌器分布需考虑射程限制及避免灌溉区域重叠。通过线段树维护最小值,优化计算效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目: 约翰的奶牛们发现山督上的草特别美味.为了维持草的生长,约翰打算安装若干喷灌器.为简化问题,山脊可以看成一维的数轴,长为L(1≤L≤10^6),而且L-定是一个偶数.每个喷灌器可以双向喷灌,并有确定的射程,该射程不短于A,不长于B,A,B(1≤A≤B≤103)都是给出的正整数.它所在位置的两边射程内,都属它的灌溉区域.现要求山脊的每一个区域都被灌溉到,而且喷灌器的灌溉区域不允许重叠, 约翰有N(1≤N≤10^3)只奶牛,每一只都有特别喜爱的草区,第i奶牛的草区是[Si,Ei],不同奶牛的草区可以重叠.现要求,每只奶牛的草区仅被一个喷灌器灌溉. 寻找最少需要的喷灌器数目.

题解:枚举每个浇灌区间的右端i当然浇灌位置只能是偶数,然后标记一下这个位置能否放入浇灌器,最后求出的浇灌区间的左端就是[max(i-2*b,0),i-2*a]注意的是如果i-2*a<0那个么这个i绝对不能当浇灌区间的右端点,最后在放到第i个位置需要浇灌器的数目就是区间[max(i-2*b,0),i-2*a]中放置用了最少浇灌器的数目加一,因为恶劣的情况下区间可能会很大那可能会超时那么需要用线段树维护一下区间的最小值


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ls 2*rt
#define rs 2*rt|1
#define mid (L+R)/2
#define lson ls,L,mid
#define rson rs,mid+1,R 
const int mx = 1e6+5;
const int inf = 0x3f3f3f3f;
struct node{
	int s,e;
}p[1005];
int T[mx<<2];
int dp[mx];
int vis[mx];
void update(int rt,int L,int R,int x,int v){
	if(L==R){
		T[rt] = min(T[rt],v);
		return;
	}
	if(x>mid)	update(rson,x,v);
	else update(lson,x,v);
	T[rt] = min(T[ls],T[rs]);
}
int query(int rt,int L,int R,int l,int r){
	if(L>=l&&R<=r)
		return T[rt];
	if(l>mid)	return query(rson,l,r);
	else if(r<=mid)	return query(lson,l,r);
	else
		return min(query(lson,l,mid),query(rson,mid+1,r));
}
int main(){
	int a,b;
	int n,l;
	while(scanf("%d%d",&n,&l)!=EOF){
		scanf("%d%d",&a,&b);
		memset(T,inf,sizeof(T));
		memset(dp,inf,sizeof(dp));
		memset(vis,0,sizeof(vis));
		for(int i = 0; i < n; i++){
			scanf("%d%d",&p[i].s,&p[i].e);
			vis[p[i].s+1]++;
			vis[p[i].e]--;
		}
		for(int i = 1; i <= l; i++)
			vis[i] += vis[i-1];
		update(1,0,l,0,0);
		dp[0] = 0;
		for(int i = 2; i <= l; i+=2)
			if(!vis[i]){
				int x = i-2*a;
				int y = i-2*b;
				if(x<0&&y<0)
					continue;
				y = max(y,0);
				dp[i] = min(dp[i],query(1,0,l,y,x)+1);
				update(1,0,l,i,dp[i]);
			}
		if(dp[l]>=inf)	puts("-1");
		else printf("%d\n",dp[l]);	
	}	
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值