在长为L(<=1000000)的草地(可看成线段)上装喷水头,喷射是以这个喷水头为中心,喷水头的喷洒半径是可调节的调节范围为[a,b]。要求草地的每个点被且只被一个喷水头覆盖,并且有些连续区间必须被某一个喷水头覆盖,而不能由多个喷头分段完全覆盖,求喷水头的最小数目。
解题思路:这道题是单调队列优化dp,状态方程很容易想到,关键是优化问题,那么我们就需要维护一个队列放dp[j],使得队列中的元素j至少比i要小2 *a, 而同时队头的元素j不能比i小2*b以上,关键在于哪些元素应该入队,哪些不应该入队。
自己写没写出来,盗了别人的代码。。
参考博客:http://blog.csdn.net/sunny606/article/details/7854362
#include<cstdio> #define L 1001000 int a,b,n,l,inf,dp[L],queue[L],head,tail,size; void insert(int idx) { tail++; while(head<tail && dp[queue[tail-1]]>dp[idx]) tail--; queue[tail]=idx; } int dpro(void) { if(b<1) return -1; dp[0]=0; size=2*b+1; head=0; tail=-1; for(int i=a; i<=b; i++) if(dp[2*i]<=inf) dp[2*i]=1; int seg = 2*b-2*a; for(int i=0; i<=seg; i++) insert(i); for(int i=2*b; i<=l; i+=2) { insert(i-a*2); while(i-queue[head]>=size) head++; if (dp[i] <= inf) dp[i]=dp[queue[head]]+1; } if(dp[l]>=inf) return -1; else return dp[l]; } int main() { while (scanf("%d%d", &n, &l)!=EOF) { scanf("%d%d", &a, &b); inf = (l/a)+9; for(int i=0; i<=l; i++) dp[i]=inf; for(int i=0; i<n; i++) { int s, e; scanf("%d%d", &s, &e); for(int j=s+1; j<e; j++) dp[j] = inf+1; } if(l&1==1) printf("-1\n"); else printf("%d\n", dpro()); } return 0; }