[NOIP2010初赛]烽火传递--单调队列优化

问题描述:
烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情,在某两座城市之间有n个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续m个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。
输入:
第一行:两个整数N,M。其中N表示烽火台的个数,M表示在连续m个烽火台中至少要有一个发出信号。接下来N行,每行一个数Wi,表示第i个烽火台发出信号所需代价。
输出:
一行,表示答案。
样例输入:
5 3
1
2
5
6
2
样例输出
4

数据范围:
对于50%的数据,M≤N≤1,000 。  
对于100%的数据,M≤N≤ 100,000,Wi≤100。

算法分析
状态:f[i]表示在i这个烽火台发出信号的最少花费
转移方程:f[i] = min(f[j] + a[i]) (i-m <= j <= i-1)
对于50%的数据:时间复杂度O(nm)
对于100%的数据:我们需要进一步优化,我们发现小括号里面的(i-m<=j<=i-1)这是一个固定的长度,正好符号我们的单调队列,求某以固定区间的最值。由于随着i的循环,每次只有一个i进入决策区间也只有一个i出决策区间,由于每次选取决策区间中的最小值,所以维护一个单调递增序列,每次取出队首元素即可。目标状态为 f[n-m+1]…f[m] 中的最小值。
动态规划代码:

//烽火传递用动规
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int f[100500],a[100500];
int n,m;
int main() {
 int ans=0x7f7f7f7f;
 memset(f, 127, sizeof(f));
 scanf("%d%d", &n, &m);
 f[0] = 0;
 for(int i = 1; i <= n; i++) 
        scanf("%d",&a[i]);
    for(int i = 1; i <= n; i++) 
     for(int j=i-m;j<=i;j++)//枚举前m-1个烽火台,从哪个烽火台传递过来 
     {
      f[i]=min(f[j]+a[i] ,f[i]);
      //这个相当于找出前m-1个最小值,可以用队列优化 
  }
    for(int i = n - m + 1; i <= n; i++) 
     ans = min(ans, f[i]);
     //从n-m+1烽火台再不需要点燃烽火台,终点都可以看到 
    printf("%d", ans);
    return 0;
}
/*
5 3
1
2
5
6
2
*/
 

用单调队列优化:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string> 
using namespace std;
const int maxn=100007;
int a[maxn],q[maxn],s[maxn];//s保存每个区间的最小值,q是模拟队列数组 
int ans=100;
int main()
{
 int n,m;
 scanf("%d%d",&n,&m);
 for(int i=1;i<=n;i++)
 {
  scanf("%d",&a[i]);
 }
 int head=0,tail=0;
 memset(s,-1,sizeof(s));//处置赋值为-1 
 q[0]=0;s[0]=0;
    for(int i=1;i<=n;i++)
    {
     if(q[head]<i-m)//队首存储下标小于当前数下标的前m个数的下标
  //注意q保存的是下标而不是数值 
     {
          head++;//队列长度超出m,队头出队 
     }
     s[i]=s[q[head]]+a[i];//队头加 
     while(head<=tail&&s[q[tail]]>s[i])
     {
      tail--;//不满足单增队列 
     }
     q[++tail]=i;//i入队 
    }
    for(int i=n-m+1;i<=n;i++)
    {
     ans=min(ans,s[i]);
    }
 printf("%d",ans);
 return 0;
}
发布了9 篇原创文章 · 获赞 0 · 访问量 113

猜你喜欢

转载自blog.csdn.net/hwdn3000/article/details/104419455