zoukankan      html  css  js  c++  java
  • hdu5643, 递归求解约瑟夫环问题

    King's Game

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 832    Accepted Submission(s): 460

    Problem Description
    In order to remember history, King plans to play losephus problem in the parade gap.He calls n(1n5000) soldiers, counterclockwise in a circle, in label 1,2,3...n.
    The first round, the first person with label 1 counts off, and the man who report number 1 is out.
    The second round, the next person of the person who is out in the last round counts off, and the man who report number 2 is out.
    The third round, the next person of the person who is out in the last round counts off, and the person who report number 3 is out.
    The N - 1 round, the next person of the person who is out in the last round counts off, and the person who report number n1 is out.
    And the last man is survivor. Do you know the label of the survivor?
     
    Input
    The first line contains a number T(0<T5000), the number of the testcases.
    For each test case, there are only one line, containing one integer n, representing the number of players.
     
    Output
    Output exactly T lines. For each test case, print the label of the survivor.
     
    Sample Input
    2
    2
    3

    Sample Output

    2
    2
     

    解题思路:

         1、当不考虑时间开销的情况下可以用循环链表结构模拟游戏的进行过程, 建立N个节点的链表并初始化,每个节点中记录其一开始的序号,循环N-1次,每次找出要删除的节点并删除,最后剩下的节点中的值输出;

         2、为了节省时间,采用效率比较高的递归算法,分析如下:

    以下重新编号均是从删除的人员的后一位开始

    第1轮中删除该轮中第1位人员,剩下的人员从1开始重新编号直到N-1作为第2轮的编号;

    第2轮中删除该轮中编号为2的人员,剩下的人员从1开始重新编号直到N-2作为第3轮的编号;

    第3轮中删除该轮中编号为3的人员,剩下的人员从1开始重新编号直到N-3作为第4轮的编号;

    ········

    第 i  - 1 轮中编号为 t1 = (i - 1) % ( N - i  + 2),由于编号是从1 ~ N- i + 2,不存在编号为0的人员所以当算出来的t1= 0时,将(N - i + 2)赋值给t1,将该轮中编号为t1的人员删除,剩下人员编号从1开始编号直到N - i + 1作为第i轮的编号;

    第 i 轮中编号为 t1 = i % ( N - i + 1),由于编号是从1 ~ N- i + 1,不存在编号为0的人员所以当算出来的t1= 0时,将(N - i + 1)赋值给t1,将该轮中编号为t1的人员删除,剩下人员编号从1开始编号直到N-i作为第i + 1轮的编号;

    第 i  + 1轮中编号为 t1 = (i + 1) % ( N - i ),由于编号是从1 ~ N- i + ,不存在编号为0的人员所以当算出来的t1= 0时,将(N - i )赋值给t1,将该轮中编号为t1的人员删除,剩下人员编号从1开始编号直到N - i - 1作为第i +2轮的编号;

    ·········

    第N轮中编号为t1 = N % (N - N + 1),由于t1 = 0,将(N- N + 1)赋值给t1

    现我们倒着推,第1次推理,最后存活的人员在第N轮中的编号为1,F(1)= 1

                             第2次推理,最后存活的人员在第N - 1轮中的编号的计算 = (第N-1轮被淘汰人员的编号+ 在第N轮被淘汰人员在第N轮的编号) % i

                             直到第N次推理所得的F(N)即为最后淘汰者在第一轮中的编号


    #include<iostream>
    using namespace std;
    int main()
    {
        int T;
        cin >> T;
        while(T--)
        {
            int N;
            cin >> N;
            int f = 1;
            for(int i = 2; i <= N; i++)
            {
                int t1 = (N - i + 1) % i;
                if(t1 == 0)
                   t1 = i;
                f = (f + t1) % i;
                if(f == 0)
                  f = i;
            }
            cout << f << endl;
        }
    }

    不考虑时间复杂度的情况下,该代码更好理解
    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    typedef struct LinkNode
    {
        int label;
        LinkNode *next;
    }LinkNode;
    
    int main()
    {
        int T;
        cin >> T;//输入例子数目 
            while(T--)
            {
                int N;
                cin>> N;//输入一共有几个人 
                LinkNode *p, *q, *head;
                for(int i = 1; i <= N; i++)
                {//创建链表 
                    if(i == 1)
                    {
                        head = (LinkNode *) malloc(sizeof(LinkNode));
                        p = q = head;
                        p->label = 1;
                        p->next = NULL;
                    }
                    else
                    {
                        q = (LinkNode *) malloc(sizeof(LinkNode));
                        q->label = i;
                        q->next = NULL;
                        p->next = q;
                        p = q;
                        if(i == N)
                        {
                            p->next = head;
                        }
                    }
                }
                for(int round = 1; round < N; round++)
                {//模拟淘汰游戏进行 
                    for(int i = 0; i < round; )
                    {
                        p = q;
                        q = q->next ;
                        i++;
                        if(i == round)
                        {
                            p->next = q->next ;
                            free(q);
                            q = p;
                        }
                    }
                }
                cout << q->label << endl;
            }
    }

     类似的可以参考http://blog.csdn.net/yanweibujian/article/details/50876631

  • 相关阅读:
    [转载]备忘:oh my zsh 的安装、更新、删除
    【转载】fedora22和win10之间的文件共享互访
    python3.7[列表] 索引切片
    注册科创版 等待生效中 测评 投资
    谷歌镜像-20190627
    debian静态地址网络配置方法
    latex高速新手教程
    Java知识点解析
    【Linux 操作系统】Ubuntu 配置 ftp freemind adb
    vs2012设置默认的全局include和lib
  • 原文地址:https://www.cnblogs.com/denghui666/p/8047633.html
Copyright © 2011-2022 走看看