poj 2373 dp(灌溉草场)

题意:在一片草场上:有一条长度为L (1 <= L <= 1,000,000,L为偶数)的线 段。 John的N (1 <= N <= 1000) 头奶牛都沿着草场上这条线段吃草,每头 牛的活动范围是一个开区间(S,E),S,E都是整数。不同奶牛的活动范围可以 有重叠。
John要在这条线段上安装喷水头灌溉草场。每个喷水头的喷洒半径可以随 意调节,调节范围是 [A,B ](1 <= A <= B <= 1000),A,B都是整数。要求
线段上的每个整点恰好位于一个喷水头的喷洒范围内 每头奶牛的活动范围要位于一个喷水头的喷洒范围内 任何喷水头的喷洒范围不可越过线段的两端(左端是0,右端是L )

请问, John 最少需要安装多少个喷水头。

思路(参考郭炜老师课件):从线段的起点向终点安装喷水头,令f(X)表示:所安装喷水头的喷洒范围 恰好覆盖直线上的区间[0 X]时,最少需要多少个喷水头。显然,X应满足下列条件 1、X为偶数
2、X所在位置不会出现奶牛,即X不属于任何一个(S,E)
3、X≥2A
4、当X>2B时,存在Y∈[X-2B X-2A]且Y满足上述三个条件,使得 f(X)=f(Y)+1。由此得到

初始条件: f(X)=1: 2A≤X≤2B 、且X位于任何奶牛的活动范围之外;

状态转移方程:f(X)=1+min{f(Y): Y∈[X-2B X-2A]、Y位于任何奶牛的活动范围 之外}: X>2B。

关键在于快速找到[X-2B X-2A]中使得f(Y)最小的元素,有优先队列维护即可。注意stl优先队列用结构体类型的写法。

再有一点需要注意是如何快速判断一个点处是否有奶牛出没,而已在之前做一遍初始化,方法见代码。

#include <cstdio>
#include <string>
#include <queue>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define INF 0x3fffffff
using namespace std;
#define N 1000005
#define INF 0x3fffffff
struct node{
    int x,f;
    node(int xx=0,int ff=0):x(xx),f(ff){}
    bool operator<(const node &x) const {
        return f>x.f;
    }
};
priority_queue<node> q;
int c[1005][2],dp[N],flag[N];
int n,m,a,b;
int main(){
    int i,k;
    memset(flag, 0, sizeof(flag));
    scanf("%d %d %d %d",&n,&m,&a,&b);
    for(i = 0;i<n;i++){
        scanf("%d %d",&c[i][0],&c[i][1]);
        flag[c[i][0]+1]++;//为了判断一个点处是否有奶牛出没
        flag[c[i][1]]--;
    }
    for(i = k = 0;i<=m;i++){
        k += flag[i];
        flag[i] = k>0;//说明有奶牛出没
        dp[i] = INF;
    }
    a <<= 1;
    b <<= 1;
    for(i = a;i<=b;i+=2)
        if(!flag[i]){//如果没有奶牛
            dp[i] = 1;
            if(b+2-a >= i)//在求F[i]的时候,要确保队列里的点x<= i - a
                q.push(node(i,1));
        }
    for(i = b+2;i<=m;i+=2){
        if(!flag[i]){
            while(!q.empty()){
                struct node tmp = q.top();
                if(tmp.x < i-b){//范围之外的点直接剔除
                    q.pop();
                    continue;
                }
                dp[i] = tmp.f+1;
                break;
            }
        }
        if(dp[i+2-a] != INF)//队列中增加一个可达下个点的点
            q.push(node(i+2-a,dp[i+2-a]));
    }
    if(dp[m] == INF)
        printf("-1\n");
    else
        printf("%d\n",dp[m]);
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值