poj 2373(单调队列优化dp)

在长为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;
}


你可能感兴趣的:(dp)