zoukankan      html  css  js  c++  java
  • [洛谷]p1996约瑟夫环 &xdoj1311

    https://www.luogu.org/problemnew/show/P1996

    约瑟夫环这个问题一直以来都是用循环链表写的,今天才知道有循环队列的写法。以下是要点:

    1.循环队列实现环的思想,其实就是队首元素出队,如果它不是该出队的元素,那么就把它继续push进queue,这样就构成了一个环的结构。

    2.用一个辅助变量来记录每次要进行的操作,比如每三个人出来选出一个人,temp设置为2,先连续两次出队再入队,此时队首就是该出队的那个元素,把它直接pop扔掉即可。循环执行,直至所有元素出队,打印结果。

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
        int n, m;
        scanf("%d %d", &n, &m);
        queue<int>Q;
        int i;
        for (i = 1; i <= n; i++)
        {
            Q.push(i);
        }
        int temp;
        int a;
        while (!Q.empty())
        {
            temp = m-1;
            while (temp)
            {
                a = Q.front();
                Q.pop();
                Q.push(a);
                temp--;
            }
            a = Q.front();
            Q.pop();
            printf("%d ", a);
        }
    }

    下面再说一下常规的循环链表写法:

    1.这个循环链表一定要是双向的链表有prior和next两个指针,如果只有一个指针,删除中间结点的操作无法完成。

    2.计数的时候就用简单粗暴的temp辅助变量来完成计数,用cnt从0加到n再置0那种方法容易出错。

    #include <bits/stdc++.h>
    using namespace std;
    typedef struct LNode
    {
        int data;
        struct LNode*prior;
        struct LNode*next;
    }LNode;
    void creat(LNode*&L, int n)
    {
        LNode*r;
        r = L;
        LNode*s;
        int i;
        r->data = 1;
        for (i = 2; i <= n; i++)
        {
            s = (LNode*)malloc(sizeof(LNode));
            s->data = i;
            r->next = s;
            s->prior = r;
            r = r->next;
        }
        r->next = L;
        L->prior = r;
    }
    void delete1(LNode*&L, int m,int n)
    {
        int cnt=1;
        LNode*r;
        LNode*s;
        r = L;
        int temp;
        while (n)
        {
            temp = m-1;
            while (temp)
            {
                r = r->next;
                temp--;
            }
                s = r;
                printf("%d ", s->data);
                r->prior->next = r->next;
                r->next->prior = r->prior;
                r = r->next;
                free(s);
                n--;
        }
        
    }
    int main()
    {
        int n, m;
        scanf("%d %d", &n, &m);
        LNode *L;
        L = (LNode*)malloc(sizeof(LNode));
        creat(L, n);
        delete1(L,m,n);
    }

    http://acm.xidian.edu.cn/problem.php?id=1311

    下面这道xdoj1311这道题很有意思,仔细想想和约瑟夫队列很相似。

    1.第一点就是要想到的是用队列实现环状结构。

    2.奇数回合抽出所有2的倍数的编号,偶数回合抽出所有3的倍数的编号。这个实现其实很简单,偶数就是1234每隔两张抽出1张牌,其实就是temp=1进行一次队首移动到队尾的操作,然后现在队首的元素就是该抽出的元素。3同理,移动队首元素两次即可。

    3.与约瑟夫环不同的是约瑟夫环是一个循环走到黑直至队空,而这个是很多回合每个回合都要把所有的牌搞一遍,仔细想想就会发现设置t也就是回合次数,可以完成所有牌的遍历,但有一点非常容易错的地方在于,执行完t次操作之后,你的队首元素不再是1(1既不是2的倍数也不是3的倍数始终未被抽出)。要实现队首元素为1就可以等效为每次都是从1开始的,与一条线性的队列没差别了。这里巧妙的用一个while的循环来保证每次队首的元素都是1.这样问题就解决了。

    4.最后要实现队列剩余元素的顺序打印就十分简单了,全放在vector中,然后sort排序,输出即可。

    整道题目像是一个加强版的约瑟夫,有些细节还是需要注意的。

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
        int T;
        scanf("%d", &T);
        int n;
        queue<int>Q;
        while (T--)
        {
            int cnt = 1;
            scanf("%d", &n);
            int i;
            int m;
            for (i = 1; i <= n; i++)
            {
                Q.push(i);
            }
            int temp;
            int t;
            while (Q.size() > 3)
            {
                if (cnt % 2 != 0)
                {
                    t = Q.size() / 2;
                    while (t--)
                    {
                        temp = 1;
                        while (temp--)
                        {
                            m = Q.front();
                            Q.pop();
                            Q.push(m);
                        }
                        Q.pop();
                    }
                    while (Q.front() != 1)
                    {
                        m = Q.front();
                        Q.pop();
                        Q.push(m);
                    }
                }
                else
                {
                    t = Q.size() / 3;
                    while (t--)
                    {
                        temp = 2;
                        while (temp--)
                        {
                            m = Q.front();
                            Q.pop();
                            Q.push(m);
                        }
                        Q.pop();
                    }
                    while (Q.front() != 1)
                    {
                        m = Q.front();
                        Q.pop();
                        Q.push(m);
                    }
                }
                cnt++;
            }
            vector<int>v;
            while (!Q.empty())
            {
                v.push_back(Q.front());
                Q.pop();
            }
            sort(v.begin(), v.end());
            for (i = 0; i < v.size(); i++)
            {
                if (i != v.size() - 1)
                    printf("%d ", v[i]);
                else
                    printf("%d", v[i]);
            }
            printf("
    ");
        }
    }
  • 相关阅读:
    ajax回调中window.open弹出的窗口会被浏览器拦截的解决方法
    javascript中常见的函数封装 :判断是否是手机,判断是否是微信,获取url地址?后面的具体参数值,毫秒格式化时间,手机端px、rem尺寸转换等
    javascript正则表达式(regular expression)
    基于jquery类库的绘制二维码的插件jquery.qrcode.js
    javascript常见的数组方法
    javascript函数,构造函数。js对象和json的区别。js中this指向问题
    vue中的组件,Component元素,自定义路由,异步数据获取
    vue中自定义指令vue.direvtive,自定义过滤器vue.filter(),vue过渡transition
    vue的表单的简单介绍 input radio checkbox等表单特性
    Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on
  • 原文地址:https://www.cnblogs.com/legendcong/p/9103128.html
Copyright © 2011-2022 走看看