美文网首页
PTA例题精析-约瑟夫问题 Josephus Problem

PTA例题精析-约瑟夫问题 Josephus Problem

作者: 苏wisdom | 来源:发表于2020-03-15 17:38 被阅读0次

0 问题描述

【人数为n,步长为m】有n个人,编号为1~n,从第一个人开始报数,从1开始报,报到m的人会死掉,然后从第m+1个人开始,重复以上过程。问最后一个人的编号是?

猴子选大王

【人数为n,步长为3】一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?正整数N(≤1000)

1 数组模拟,m=3

这里使用数组暴力模拟的问题在于,已经被淘汰的猴子仍然会被循环到

#include <stdio.h>
int a[1001];// 1表示淘汰 
int main(){
    int n = 0,s=0,count=0;
    int i = 0; // 数组下标 
    scanf("%d", &n);
    while(s != n-1){ // 淘汰猴子的数量达到n-1时退出
        i++;
        if (i>n){
            i = 1;
        }
        if(a[i] == 0){ // 只判断剩下的猴子 
            count++;
            if (count %3==0){
                a[i] = 1;
                s++; // 每次淘汰一只猴子,直到s==n-1,剩下最后一只 
            } 
        } 
        
    }
    for (int j=1;j<=n;j++){
        if (a[j]==0){
            printf("%d",j);
        }
    }
    return(0);
}

2 链表模拟,m=3

image.png

链表方法很好理解,首尾相连成环,n个人中会淘汰n-1个人,所以外层循环是n-1,链表使用curr = curr->Next 2次,那么,就找到了数3的人,把它从链表中删除,这次外层循环就走完了,剩下n-2个人。

这里使用了单向链表,用一个last指向了出圈者的上一个人,以便于对出圈者进行链表删除操作。也可以考虑使用双向链表。时间复杂度O(nm)

#include <stdio.h>
#include <stdlib.h>

typedef struct Node* Link;
struct Node{
    int Num;
    Link Next;
};
int main(){
    int n=0;
    scanf("%d", &n);
    Link head = (Link) malloc(sizeof(struct Node));
    head->Num = 1;
    head->Next = NULL;
    Link curr = head;
    for (int i=2;i<=n;i++){
        Link node = (Link) malloc(sizeof(struct Node));
        node->Num = i;
        node->Next = NULL;
        curr->Next = node;
        curr = curr->Next;
    }
    curr->Next = head;
    Link last = curr;
    curr = head;

    // operate
    for (int i=1;i<n;i++){
        for (int j=1;j<3;j++){
            last = curr;
            curr = curr->Next;
        }
        printf("出圈:%d\n",curr->Num);
        Link Temp = curr;
        last->Next = curr->Next;
        free(Temp);
        curr = last->Next;
    }
    printf("胜利者:%d\n",curr->Num);
    return(0);
}

3 递归法,m=3

使用递归求解问题需要找到三个关键点,从而找到对应的递推公式。

  1. 该问题的解可以分解为几个子问题?
  2. 确保问题本身和子问题,除了数据规模不同,求解思路完全一样
  3. 确定递归终止条件

待着上述3个关键点,我们来看约瑟芬问题如何用递归求解。

我们从0开始做下标。
f(n,m)表示n个人数m时问题的解,那么f(n-1,m)是n-1个人数m时问题的解。
显然我们知道不管m等于多少f(1) = 0
假设f(n-1)的答案(胜利者的下标)已经求出,那么思考一下f(n-1)的胜利者的下标位置和f(n)胜利者的下标位置之间有什么关系呢?

image.png

图中最上方的两行黄色,列出了n从1~11时,对应的f(n,3)结果。

  • 下方的图拿n=11个人编号0~10,第一次数的时候从0数到2数了3个数,那么2就被踢出去了,标记为红色,之后永远不可能数到2了,下方设置为灰色。剩下10个人。
  • 剩下10个数编号0~9,编号为3的人是这10个人队伍的头,从0开始重新报数。仍然是报到的人被踢出去,剩下9个人0~8。

所以我们可以看到f(n)和f(n-1)下标之间有相差为m的关系。
f(k) = ( f(k-1)+3 )%k ,效率O(n)
理解这个递推式的核心在于

  • 关注胜利者的下标位置是怎么变的。
  • 每次去掉一个人以后,下一个报数的人从0开始编号。

如果下一个报数的人,不从0开始编号会怎么样呢?如下图看到,n=11的时候,f(11,3)是从0开始报数的,到编号2的时候被踢出去,剩下10人。
10人中,编号为3的人是这10个人队伍的头,但是我们给他编号9。他仍然是第一个报数,报了第三个数的人(编号1)将被踢出去。对于这10个人来说,是从最后一个编号开始报数的,这与题意不符合,所以它的值根本不能表示f(10,3)

image.png

分析了这么多,我们发现:

  1. f(n,m) 可以分解成1个子问题f(n-1,m)
  2. f(n,m)的求解思路和f(n-1,m)一样,只是数据规模不同
  3. 递归终止条件为f(1)=0
  4. 递推公式为 f(n,m) = (f(n-1,m) + m)%n , f(1)=0

最后,题目要求下标从1开始,所以返回ans+1

#include <stdio.h>

int main(){
    int n = 0,m=3;
    scanf("%d", &n);
    int ans = 0;
    for (int i=1;i<=n;i++){
        ans = (ans + m)%i;
    }
    printf("%d", ans+1);
    return(0);
}

相关文章

  • PTA例题精析-约瑟夫问题 Josephus Problem

    0 问题描述 【人数为n,步长为m】有n个人,编号为1~n,从第一个人开始报数,从1开始报,报到m的人会死掉,然后...

  • python中队列的应用:约瑟夫斯问题

    著名的约瑟夫斯问题(Josephus Problem)是应用队列(确切地说,是循环队列)的典型案例。约瑟夫斯问题讲...

  • 01.约瑟夫环

    约瑟夫环问题(Josephus Problem) 据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领...

  • 小朋友学数据结构(1):约瑟夫环的三种解法

    约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提出的,他参加并记录了公元66—70年...

  • 一个经典约瑟夫问题的分析与解答

    一、约瑟夫问题的由来 约瑟夫问题(Josephus)是由古罗马的史学家约瑟夫(全名Titus Flavius Jo...

  • [数据结构]Josephus problem

    1.Josephus问题 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示...

  • 约瑟夫环问题

    参考文章 约瑟夫环之二(用递归的思想解决Josephus问题) 解释 解法 初始情况: 0, 1, 2 ........

  • 约瑟夫环问题

    介绍 约瑟夫(Josephus)问题是一种很经典的问题。小时候在一些益智书上看过。 约瑟夫说了一个古罗马的故事,有...

  • day03-约瑟夫环

    约瑟夫环问题: 问题来历 据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太...

  • josephus问题

    线性表是数据结构的中很常见的结构,其中一种就是顺序表,python已经内置了顺序表。list就是循序表的的实现。下...

网友评论

      本文标题:PTA例题精析-约瑟夫问题 Josephus Problem

      本文链接:https://www.haomeiwen.com/subject/jgzeehtx.html