• 基础数据结构3.2——队列


    题目上添加了超链接,大家点一下题目就会自动跳转到Poj原题界面~~              冲鸭冲鸭ヾ(◍°∇°◍)ノ゙。

    前言:

    队列相较于其它数据结构的特点是先进先出,通常也是通过数组、链表实现。

    通过数组实现时,为解决伪溢出问题,常需要采用循环队列。做题时用数组实现就足以应对绝大部分题目。

    常见题型有模拟单调队列(挺难的,也是很多进阶优化算法的基础)、以及后续的搜索题....很重要,需要打好基础。

    最后一道题2823尤为经典重要。相关课程我看的少,有感觉讲的特别好、特别浅显深刻的,欢迎大家留言分享(好想自己录一个)

    3.2.1 Card Trick (3032)

    题意:一堆牌有n张,从牌堆顶部开始,第i次将i张牌放到牌底,然后将新的牌顶的牌从牌堆中取走。求取走的n张牌在原牌堆中的位置。

    小笔记:简单模拟

    #include <cstdio>
    #include <queue>
    using namespace std;
    int main()
    {
        int t;
        scanf("%d", &t);
        while (t--)
        {
            queue<int> Q;
            int a[15]; //记录每张牌在原队列中的位置
            int k = 1; //记录取牌顺序
            int n;
            scanf("%d", &n);
            for (int i = 1; i <= n; i++)
                Q.push(i); //将所有牌入队列
            for (int i = 1; i <= n; i++)
            {
                for (int j = 1; j <= i; j++)
                {
                    Q.push(Q.front());
                    Q.pop();
                }
                a[Q.front()] = k++;
                Q.pop();
            }
            for (int i = 1; i <= n; i++)
                printf("%d ", a[i]);
            printf("
    ");
        }
        return 0;
    }
    

      

    3.2.2 Card Stacking (3629)

    题意:N个玩家围成一圈打牌,牌堆共有K张牌(K为N的倍数),其中包含M=K/N张好牌和K-M张坏牌。然后和上一题差不多。

    小笔记:模拟,发到手里的牌直接出列,其他牌再次入列,发到发牌人手中的牌记录这种牌的最初编号。

    #include <cstdio>
    #include <queue>
    #include <algorithm>
    using namespace std;
    int main()
    {
        queue<int> Q;
        int a[50005]; //记录好牌的编号
        int n, k, p;
        scanf("%d%d%d", &n, &k, &p);
        for (int i = 1; i <= k; i++)
            Q.push(i);
        int m;
        for (m = 0; m < k / n; m++)
            for (int i = 1; i <= n; i++)
            {
                if (i == n)
                    a[m] = Q.front();
                Q.pop();
                for (int j = 0; j < p; j++)
                {
                    Q.push(Q.front());
                    Q.pop();
                }
            }
        sort(a, a + m);
        for (int i = 0; i < m; i++)
            printf("%d
    ", a[i]);
        return 0;
    }
    

      

    3.2.3 Printer Queue (3125)

    题意:一个队列包含n个打印作业,每个作业有一个优先级(1~9),从队列头开始,如果该作业的优先级比队列中其他所有作业的优先级高,则打印该作业并出列,否则将该作业放入队列尾;打印作业花费时间为1,其他操作不花费时间。求一个队列中给定作业m,等待到打印完该作业共需要多长时间。

    小笔记:模拟,每次取队列头,检查队列中是否有比它优先级高的作业,有的话将该作业放入队列尾,否则时间加1后出队列。处理到指定作业m的时候,如果队列中没有比它优先级高的作业,则时间加1,打印该作业;否则将它移到队尾,继续判断下一个作业。

    #include <cstdio>
    #include <vector>
    using namespace std;
    struct job
    {
        int v; //作业的序号
        int p; //作业的优先级
        job(int a, int b) : v(a), p(b) {}
    };
    //检查队列Q中是否有优先级比x高的项,如果有,输出真,否则输出假
    bool check(vector<job> Q, int x, unsigned int i)
    {
        while (i < Q.size())
            if (x < Q[i++].p)
                return true;
        return false;
    }
    int main()
    {
        int t;
        scanf("%d", &t);
        while (t--)
        {
    //使用STL中的向量vector 实现队列,利用其push_back操作向队列尾部加入数据
            vector<job> Q;
            int n, m;
            scanf("%d%d", &n, &m);
            for (int i = 0, p; i < n; i++)
            {
                scanf("%d", &p);
                Q.push_back(job(i, p));
            }
            int ans = 1;
    for (int k = 0; check(Q, Q[k].p, k) || Q[k].v != m; k++)
            {
                if (check(Q, Q[k].p, k))
                    Q.push_back(Q[k]);
                else
                    ans++;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    

      

    3.2.4 Team Queue (2259)

    题意:共有t组元素进行队列操作。

    入列操作:元素进入队列之前先从头检查队列中是否有同组的元素,如果有,直接排到同组元素后面,否则排到队列尾。

    出列操作:直接取出队列头的元素。

    小笔记:按照题意进行队列模拟,一共有 t 组队列Q[1…t], x 所在的组为T[x],用一个队列TQ记录当前元素所在组的信息。

    #include <cstdio>
    #include <queue>
    using namespace std;
    const int N = 1001;
    int T[1000000]; //元素与队列号的映射
    int main()
    {
        int t, k = 0;
        while (scanf("%d", &t) && t)
        {
            printf("Scenario #%d
    ", ++k);
            bool v[N]; //标识是否有同组元素
            for (int i = 0; i < t; i++)
            {
                int n;
                scanf("%d", &n);
                v[i] = false;
                while (n--)
                {
                    int x;
                    scanf("%d", &x);
                    T[x] = i;
                }
            }
            queue<int> Q[N]; 	//存储每个组
            queue<int> TQ;   //存储组号
            char cmd[10];
            while (scanf("%s", cmd) && cmd[0] != 'S')
            {
                if (cmd[0] == 'E')
                {
                    int x;
                    scanf("%d", &x);
                    int i = T[x];
                    if (!v[i])
                    {
                        v[i] = true;
                        TQ.push(i); //将元素x所在组号T[x]放入队列TQ
                    }
                    Q[i].push(x); // 将元素x放入队列Q[T[x]]
                }
                else if (cmd[0] == 'D')
                {
                    int i = TQ.front();  //从TQ队列头找到组号i
                    printf("%d
    ", Q[i].front()); //输出Q[i]队列头元素
                    Q[i].pop();
                    if (Q[i].empty())
                    {
                        TQ.pop();
                        v[i] = false;
                    }
                }
            }
            printf("
    ");
        }
        return 0;
    }
    

      

    3.2.5 Sliding Window (2823)

    题意:数组a[1…n]有n个数字,依次计算a[1…k]到A[n-k+1…n]区间的最大值和最小值。

    小笔记:这道题特别重要,十分精华。一种方法是滑动窗口、单调队列的思想应用,一定要掌握。到后面我们还会学习线段树,也是对这种反复问询区间问题的杀招。

    #include <cstdio>
    #include <queue>
    using namespace std;
    int a[1000005];
    int main()
    {
        int n, k;
        scanf("%d%d", &n, &k);
        //求区间最小值
        deque<int> minQ;
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            while (!minQ.empty() && a[i] < a[minQ.back()])
                minQ.pop_back();
            minQ.push_back(i);
            if (minQ.front() < i - k + 1)
                minQ.pop_front();
            if (i >= k)
                printf("%d ", a[minQ.front()]);
        }
        printf("
    ");
        //求区间最大值
        deque<int> maxQ;
        for (int i = 1; i <= n; i++)
        {
            while (!maxQ.empty() && a[i] > a[maxQ.back()])
                maxQ.pop_back();
            maxQ.push_back(i);
            if (maxQ.front() < i - k + 1)
                maxQ.pop_front();
            if (i >= k)
                printf("%d ", a[maxQ.front()]);
        }
        printf("
    ");
        return 0;
    }
    

      

     
  • 相关阅读:
    MongoDB查询语句 (增、删、改、查)
    MongoDB简单查询语句
    jquery Select Change事件
    c# 远程监控(4) 接收端 RTP包重组 分屏显示
    c# 远程监控(3) RTP协议 RTP.NET.DLL
    c# 远程监控(1) 大纲
    c# 远程监控(2) 摄像头调研及模拟
    TortoiseGit记住用户名和密码
    winform ListView和DataGridView实现分页
    制作符合平台的CodeSmith代码生产模版
  • 原文地址:https://www.cnblogs.com/thx2199/p/15116553.html
Copyright © 2020-2023  润新知