单调队列可以用于优化多重背包。
可以在O(n)的时间复杂度内求解某一区间内的最值。
比如, 给出 n 个数, 求出数组中任何一个长度为m的区间中 的最大值 和 最小值
暴力的算法是, 两个循环,内层循环对 m 进行遍历,求出最值。 但这样重复遍历了很多元素。如何省去重复的步骤呢?
单调队列的思想是 队列里元素大小一定是单调递增或者单调递减的,且保存的是所有含有这个最值的区间的最值。这样就避免了重复遍历。
设置两个队列分别保存当前区间内的最大值和最小值。
#include <stdio.h>
#include <iostream>
using namespace std;
const int MAXN = 100001;
int N, K, data[MAXN], qmin[MAXN], qmax[MAXN], savemin[MAXN], savemax[MAXN];
int main(){
cin>>N>>K;
for(int i = 1; i <=N; i++){ //数组下标从 1 开始
cin>>data[i];
}
int l = 1, r = 0, l1 = 1, r1 = 0, cnt = 1; // l r l1 r1 分别代表qmax、qmin 的队头指针和队尾指针
for(int i = 1; i<=N; i++){
while(l <= r && data[i] >= data[qmax[r]]) r--; //比队列中元素值大, 更新.
qmax[++r] = i; //保存当前最大值位置。
while(l1 <= r1 && data[i] <= data[qmin[r1]]) r1--;
qmin[++r1] = i;
if(i>=K){ //窗口形成, 开始保存每个窗口的最大值最小值
while(qmax[l] <= i - K) l++;
while(qmin[l1] <= i - K) l1++;
savemax[cnt] = data[qmax[l]];
savemin[cnt] = data[qmin[l1]];
cnt++;
}
}
for(int i = 1; i < cnt; i++){
cout<<savemax[i]<<" ";
}
cout<<endl;
for(int i = 1; i< cnt; i++){
cout<<savemin[i]<<" ";
}
cout<<endl;
return 0;
}
924

被折叠的 条评论
为什么被折叠?



