单调队列

1.例子

  我们先讲单调队列在干嘛。
  数列为:6 4 10 10 8 6 4 2 12 14,N=10,K=3;我们要构造一个长度为K的单调递减队列:
  首先,将6和它的位置0放入队列中,用(6,10)表示,每一步变化如下:
插入6:(6,0);
插入4:(6,0),(4,1);
插入10:(10,2);
插入第二个10,保留后面那个:(10,3);
插入8:(10,3),(8,4);
插入6:(10,3),(8,4),(6,5);
插入4,之前的10已经超出范围所以排掉:(8,4),(6,5),(4,6);
插入2,同理:(6,5),(4,6),(2,7);
插入12:(12,8);
插入14:(14,9);
那么f(i)就是第i步时队列当中的首元素:6,6,10,10,10,10,8,6,12,14
  单调递减队列是这么一个队列(首元素最大,单调递增队列则相反),它的头元素一直是队列当中的最大值,而且队列中的值是按照递减的顺序排列的。我们可以从队列的末尾插入一个元素,可以从队列的两端删除元素。(双端队列)
  单调队列的操作:
  1.若队列为空,将A[i]从队尾入队
  2.若队列不为空,将比A[i]小或等的元素都从队尾弹出,然后把A[i]入队
  3.若队列不为空且A[i]小于队尾,则直接从队尾把A[i]入队

if(q.empty())
q.push_back(A[i]);
else if(q.back()<=A[i]){
while((!q.empty())&&q.back()<=A[i]){
q.pop_back();
}
q.push_back(A[i]);
}
else
q.push_back(A[i]);

[注]:上面是单减队列,单增队列则相反

2.例题

Description:
  烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,定代价。
  为了使情报准确地传递,在连续m个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。
Input:
  第一行:两个整数N,M。其中N表示烽火台的个数,M表示在连续m个烽火台中至少要有一个发出信号。
  接下来N行,每行一个数Wi,表示第i个烽火台发出信号所需代价。
Sample Input:
5 3
1
2
5
6
2
Sample Output:
4
Analyse:
  设f[i]表示i必须选时最小代价。
  初值: f[0]=0 f[1..n]=∞
  方程: f[i]=min(f[j])+w[i]并且max(0,i-m)≤j<i
  最后在f[n-m+1..n]中取最小值即答案,时间复杂度O(nm)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m;
int w[100001];
int que[100001],head=0,tail=0;
int f[100001];
int main()
{
scanf("%d%d",&n,&m);
int i,j;
for (i=1;i<=n;++i)
scanf("%d",&w[i]);
memset(f,127,sizeof f);//初始化无限大
f[0]=0;
que[0]=0;
for (i=1;i<=n;++i)
{
if (que[head]<i-m)
++head;//将超出范围的队头删掉
f[i]=f[que[head]]+w[i];//转移(用队头)
while (head<=tail && f[que[tail]]>f[i])
--tail;//将不比它优的全部删掉
que[++tail]=i;//将它加进队尾
}
int ans=0x7f7f7f7f;
for (i=n-m+1;i<=n;++i)
ans=min(ans,f[i]);
printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值