poj 2373 dp(灌溉草场)

来源:互联网 发布:高级算法工程师 编辑:程序博客网 时间:2024/06/05 00:49
题意:在一片草场上:有一条长度为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 0x3fffffffusing namespace std;#define N 1000005#define INF 0x3fffffffstruct 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 0
原创粉丝点击