hdu5643, 递归求解约瑟夫环问题

Posted hui666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 n?1 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

以上是关于hdu5643, 递归求解约瑟夫环问题的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5643 King's Game | 约瑟夫环变形

python类约瑟夫环原创问题求解 求大神

HDU5643-King's Game

约瑟夫环问题求解

hdu3089 Josephus again|快速约瑟夫环

hdu1443 Joseph---约瑟夫环