• 单调队列


    单调队列,就是队列里的元素是单调递增或者单调递减的。

    那就有人问了,这和优先队列有什么区别。

    单调队列里的单调递增(递减)不止是值的单调递增(递减),下标也是单调递增的。

    我们来看单调队列怎么维护的,就知道单调队列是什么东西了。

    这里以单调递增队列为例。

    将数组a[1->n]里面的元素依次入队列。   如果要入队的元素大于队尾元素,那么就将该元素入队列, 如果该元素小于队伍元素,

    那么就将队尾元素不断地出队列,直到队伍元素大于该元素,或者队列为空为止。

    所以单调递增队列里面的元素不止值是递增的,下标也是递增的

    foj1894

    要我们求队列中的最大值,因为队列是无序的,所以每次查询的复杂度都是O(N),这肯定是不行的

    所以我们只要维护一个单调递减队列就行了(因为单调递减队列可以保留最大值,而单调递增队列不行,比如 1 2 4 3  如果用单调递增队列,那么当3插入时,队列中只有3)

    对于Q命令,如果队列不为空,我们只要输出队首元素即可。

    对于G命令,将cnt2++, 然后将队列中id<=cnt2的元素出队列

    对于C命令, 即维护一个单调队列

    为什么当加入一个元素时,当队尾元素小于插入元素时,队尾元素可以删去呢。 因为插入的元素比队尾元素大,且序号比队尾元素更靠后,

    所以当该元素存在时,是不会选取队尾元素的,即该元素是更优的,所以可以删除队尾元素

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <algorithm>
     5 #include <iostream>
     6 #include <queue>
     7 #include <stack>
     8 #include <vector>
     9 #include <map>
    10 #include <set>
    11 #include <string>
    12 #include <math.h>
    13 using namespace std;
    14 #pragma warning(disable:4996)
    15 typedef long long LL;                   
    16 const int INF = 1<<30;
    17 /*
    18 
    19 */
    20 struct node
    21 {
    22     int value;
    23     int id;
    24 };
    25 node q[1000000+10];
    26 int head,tail;
    27 int main()
    28 {
    29    int t,i,rp,cnt,cnt2;
    30    char str[111];
    31    scanf("%d",&t);
    32    while(t--)
    33    {
    34         scanf("%s",str);
    35         head = tail = cnt = cnt2 = 0;
    36         while(true)
    37         {
    38             scanf("%s",str);
    39             if(str[0]=='E')
    40                 break;
    41             if(str[0]=='C')
    42             {
    43                 cnt++;
    44                 scanf("%s%d",str,&rp);
    45                 
    46                 while(tail>head && q[tail-1].value < rp)
    47                 {
    48                     tail--;
    49                 }
    50                 q[tail].id = cnt;
    51                 q[tail++].value = rp;
    52                 
    53                 
    54             }
    55             else if(str[0]=='G')
    56             {
    57                 cnt2++;
    58                 while(head<tail && q[head].id<=cnt2)
    59                     head++;
    60             }
    61             else
    62             {
    63                 if(head!=tail)
    64                     printf("%d
    ",q[head].value);
    65                 else
    66                     puts("-1");
    67             }
    68         }
    69    }
    70     return 0;
    71 }
    View Code

     烽火传递

    描述 Description  

        烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情。在某两座城市之间有n个烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确的传递,在m个烽火台中至少要有一个发出信号。现输入n、m和每个烽火台发出的信号的代价,请计算总共最少需要话费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确的传递!!!

    输入格式 Input Format

             第一行有两个数n,m分别表示n个烽火台,在m个烽火台中至少要有一个发出信号。

             第二行为n个数,表示每一个烽火台的代价。

    输出格式 Output Format     

            一个数,即最小代价。       

    样例

    5 3

    1 2 5 6 2

    4

    dp[i] 表示点燃第i个烽火台所需要的最小代价

    那么dp[i] = min{dp[j] | i-m<=j <i } + a[i]

    那么代码如下

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <algorithm>
     5 #include <iostream>
     6 #include <queue>
     7 #include <stack>
     8 #include <vector>
     9 #include <map>
    10 #include <set>
    11 #include <string>
    12 #include <math.h>
    13 using namespace std;
    14 #pragma warning(disable:4996)
    15 typedef long long LL;                   
    16 const int INF = 1<<30;
    17 /*
    18 
    19 */
    20 const int N = 1000 + 10;
    21 int a[N];
    22 int dp[N];
    23 void solve(int n, int m)
    24 {
    25     for(int i=0; i<=n; ++i)
    26         dp[i] = INF;
    27     dp[0] = 0;
    28     /*时间复杂度是n*m*/
    29     for(int i=1; i<=n; ++i)
    30         for(int j=i-m; j<i; ++j)
    31         {
    32             if(j<0) continue;
    33             dp[i] = min(a[i]+dp[j],dp[i]);
    34         }
    35 }
    36 int main()
    37 {
    38    int n,m,i;
    39    while(scanf("%d%d",&n,&m)!=EOF)
    40    {
    41         for(i=1; i<=n; ++i)
    42             scanf("%d",&a[i]);
    43         solve(n,m);
    44         int Min = INF;
    45         for(i=1; i<=n; ++i)
    46             printf("%d ",dp[i]);
    47         puts("");
    48         for(i=(n-m+1); i<=n; ++i)
    49             Min = min(Min, dp[i]);
    50         printf("%d
    ",Min);
    51    }
    52 
    53     return 0;
    54 }
    View Code

     从中可以看出,求解dp[i]的时候,我们需要求解出区间[i-m,i)的最小值, 所以这个最小值可以用单调递增队列来维护, 

    求区间最小值需要O(n)的时间复杂度,使用单调递增队列来维护,那么只需要O(1)的复杂度, 所以这就是为什么说使用单调队列,能够将时间复杂度降低1维

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <algorithm>
     5 #include <iostream>
     6 #include <queue>
     7 #include <stack>
     8 #include <vector>
     9 #include <map>
    10 #include <set>
    11 #include <string>
    12 #include <math.h>
    13 using namespace std;
    14 #pragma warning(disable:4996)
    15 typedef long long LL;                   
    16 const int INF = 1<<30;
    17 /*
    18 
    19 */
    20 const int N = 1000 + 10;
    21 struct node
    22 {
    23     int value;
    24     int id;
    25 }q[N];
    26 int head,tail;
    27 int a[N];
    28 int dp[N];
    29 void solve(int n, int m)
    30 {
    31     head = tail = 0;
    32     for(int i=0; i<=n; ++i)
    33         dp[i] = INF;
    34     dp[0] = 0;
    35     q[tail].value = 0;
    36     q[tail++].id = 0;
    37     for(int i=1; i<=n; ++i)
    38     {
    39         /*for(int j=i-m; j<i; ++j)
    40         {
    41             if(j<0) continue;
    42             dp[i] = min(a[i]+dp[j],dp[i]);//这里要得到dp[j]的最小值,我们可以用单调递增队列来维护,哈哈哈
    43         }*/
    44         while(head<tail && q[head].id < i-m)
    45             head++;
    46         dp[i] = q[head].value + a[i];
    47         while(head<tail && q[tail-1].value > dp[i])
    48             tail--;
    49         q[tail].value = dp[i];
    50         q[tail++].id = i;
    51         
    52     }    
    53 }
    54 int main()
    55 {
    56    int n,m,i;
    57    while(scanf("%d%d",&n,&m)!=EOF)
    58    {
    59         for(i=1; i<=n; ++i)
    60             scanf("%d",&a[i]);
    61         solve(n,m);
    62         int Min = INF;
    63         for(i=1; i<=n; ++i)
    64             printf("%d ",dp[i]);
    65         puts("");
    66         for(i=(n-m+1); i<=n; ++i)
    67             Min = min(Min, dp[i]);
    68         printf("%d
    ",Min);
    69    }
    70 
    71     return 0;
    72 }
    View Code
  • 相关阅读:
    ORM查询相关的操作
    分享一些珍藏和网上搜集的一些接码平台
    DRF: serializers ModelSerializer的序列化中model在有外键的情况下显示name代替显示id的几种方式
    Django Rest framework中序列化A表时怎么获取B表的数据
    10步入门Django Rest framework后端接口框架
    Django Rest framework后端接口框架,常用的子类视图
    redis学习(九)——数据持久化
    Java8之lambda表达式
    Java多线程(九)—— interrupt()和线程终止方式
    redis学习(八)——redis应用场景
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4518345.html
Copyright © 2020-2023  润新知