单调队列入门(Jacob's zone)

来源:互联网 发布:寰宇人生软件下载 编辑:程序博客网 时间:2024/05/16 10:55

单调队列是从数列前扫到数列后...维护一个最值或者一个所需的最优解之类的...每次的最优解都是在队列的头....所以要一直维护队列..使其从头到尾都是单调的..要能保证如果当前头要出去了...后面的元素能马上顶上来作为头...

   就拿POJ2823来举例....题目要求是给了一串n个数...从左到右每次框k个连续数..问每次框的数中最大数和最小数是什么..样例输入输出:

Sample Input

8 3 1 3 
-1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 3
3 3 5 5 6 7
  

   就拿样例说....准备一个队列...Myqueue...h代表队列头( 里面存的是下标不是数..为了是判断队首出列)..p代表队列尾..初始值h=1,p=0...就拿每次要一段最小值的队列变化过程来描述一下:

  1、插入第1个数    Myqueue = { 1 }  h=1;  p=1  小于所给的框..还不需输出

  2、插入第2个数    Myqueue= { 1 2 } h=1; p=2    (  因为2号元素比1号元素大...先排到后面 )   小于所给的框..还不需输出

  3、插入第3个数   Myqueue= { 3 }  h=1; p=1;   (  因为3号元素为-1比1号元素的1和2号元素的3都要小~~所以一直挤到最前面...1,2都出列 )    输出 a[ Myqueue[h] ]的值 -1

  4 、插入第4个数   Myqueue={ 4 } h=1; p=1;  (   因为4号元素比3号元素小....所以挤掉3号元素 )  输出 a[ Myqueue[h] ]的值 -3

  5、插入第5个数   Myqueue={ 4 5 }   h=1; p=2   ( 因为5号元素比4号元素大...先排到后面 )    输出 a[ Myqueue[h] ]的值 -3

  6、插入第6个数   Myqueue={4 6 }    h=1; p=2 ( 因为6号元素比5号元素小....但是又没有4号元素小..所以只能挤掉5号元素 )  输出 a[ Myqueue[h] ]的值 -3

  7、插入第7个数   Myqueue={ 6 7 }  h=2; p=3 { 这里为什么4出列了?因为4到7已经不能被所给的范围框住了...所以4要出列..然后继续操作...因为7号元素比6号元素大...先排到后面)   输出 a[ Myqueue[h] ]的值 3

  8、插入第8个数   Myqueue={6 7 8 } h=2; p=4; { 因为8号元素比7号元素和6号元素都要大...所以放到后面... )   输出 a[ Myqueue[h] ]的值 3


    还有一点要特别注意!!!如果后面的数和h[p]元素的数相等时...也要挤掉h[p]的....因为这个我WA了一次...囧....

   这道题用单调队列来跑只要5000MS..的确快了不少..但看大牛们还能更快...想知道怎么做到的...


   PS:...有个地方一定要注意...每次插入新数到队列都要从队尾往队首扫..扫到比自己小的就确定位置..扫到比自大的就把这个大的数给挤掉.....如果从前往后扫....例如

   1 2 3 4 5 6 7 8  9 ..... 很长一列...要插入一个很大的数...从前一直遍历到最后面..才确定位置..这不是关键..关键是这一路过去..什么操作都没有做..白白扫了一大片空间...而从后往前扫...要么确定位置...要么踢到元素...总是在操作..所以必须要从后往前来判断并插入.... 


/*    Title: POJ 2823    Author: RudyLu5    Date: 2012.02.28    Algorithm: Monotonous Queue    License:GPL    Night Gathers, and My Watch Begins, it shall Never End until My Death*/#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cmath>using namespace std;int n, k;int data[1000005];int myQueue[1000005];void Solve(){    int i, j, head = 1, rear = 0, t;    myQueue[head] = 1;    for(i = 1; i <= n; ++i)    {        if(i - myQueue[head] == k) head++;        if(rear == head - 1 || data[i] > data[myQueue[rear]]) myQueue[++rear] = i;        else        {            while(rear >= head && data[i] <= data[myQueue[rear]])            {                myQueue[rear--] = i;            }            rear++;        }        if(i >= k) printf("%d ", data[myQueue[head]]);    }    printf("\n");    head = 1, rear = 0, myQueue[1] = 1;    for(i = 1; i <= n; ++i)    {        if(i - myQueue[head] == k) head++;        if(rear < head || data[i] < data[myQueue[rear]]) myQueue[++rear] = i;        else        {            while(rear >= head && data[i] >= data[myQueue[rear]])            {                myQueue[rear--]=i;            }            rear++;        }        if(i >= k) printf("%d ", data[myQueue[head]]);    }    printf("\n");}int main(){    int i;    scanf("%d%d", &n, &k);    for(i = 1; i <= n; ++i)    {        scanf("%d", &data[i]);    }    Solve();    return 0;}


原创粉丝点击