详解基于C++实现约瑟夫环问题的三种解法

详解基于C++实现约瑟夫环问题的三种解法

约瑟夫问题

约瑟夫问题是一个经典的问题,是一个圆圈里面有$n$个数字,从中每次删除第$m$个数字,求出每次删除的数字。简单的说,约瑟夫问题就是$n$个人围成一圈,从第一个人开始报数,报到$m$的人出圈,直到计算到最后一个人。

解法一:使用递推(模拟游戏过程)

思路:利用递归的思想模拟即可。假如最后剩下一个数据,则保留该数据,否则位置为 $s=(f+m)\ mod\ i $,$f$表示上一轮已经被删除数字的位置,$i$表示上一轮剩余数字个数,$m$为给定的数字。

代码:

int Josephus(int n, int m) {
    if (n == 1) {
        return 1;
    }
    return (Josephus(n - 1, m) + m - 1) % n + 1;
}

递归较为简便,但是处理的数据规模过大,会引起栈溢出等问题。

解法二:循环链表

思路:使用循环链表模拟过程,进行删除操作,直到链表剩下一个节点。

代码:

#include <iostream>
using namespace std;

struct Node {
    int val;
    Node* next;
};

int Josephus(int n, int m) {
    Node* head = new Node{1, nullptr};
    Node* cur = head;
    for (int i = 2; i <= n; i++) {
        cur->next = new Node{i, nullptr};
        cur = cur->next;
    }
    cur->next = head;
    while (head->next != head) {
        int cnt = m % (n--);
        if (cnt == 0) {
            cnt = n;
        }
        Node* pre;
        for (pre = head; pre->next != head; pre = pre->next) {
            if (--cnt == 0) {
                break;
            }
        }
        Node* temp = pre->next;
        pre->next = temp->next;
        head = temp->next;
        delete temp;
    }
    int res = head->val;
    delete head;
    return res;
}

int main() {
    cout << Josephus(5, 3) << endl;    // 输出3
    cout << Josephus(8, 4) << endl;    // 输出6
    return 0;
}

解法三:数学归纳

思路:可以通过利用数学归纳法来证明一种对称性,然后根据对称性来推导出约瑟夫环问题的答案。设 $f(n)$ 表示当有$n$个人时最后留下的人在数列中的位置,则:

当 $n=1$ 时,$f(1)=0$。

当 $n>1$ 时,将编号改为从 $0$ 开始,第一个人编号为 $0$ ,对 $n-1$ 取模,设结果为 $x$,则:

$$ f(n,m)=\left{\begin{aligned} & 0 & n=1 \ & \left(f(n-1,m)+m\right)\ \% \ n & n>1 \end{aligned}\right. $$

代码:

int Josephus(int n, int m) {
    int res = 0;
    for (int i = 2; i <= n; i++) {
        res = (res + m) % i;
    }
    return res + 1;
}

示例说明

例如,有 $5$ 个人 $(0, 1, 2, 3, 4)$ 依次报数,编号为 $0$ 的人从 $1$ 开始报数,假设报到 $3$ 的人出局,依次出局的顺序为 $2, 0, 4, 3$,因此最后剩下的是编号为 $1$ 的人。

可以通过调用以下代码进行验证:

cout << Josephus(5, 3) << endl;

输出为 $3$。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解基于C++实现约瑟夫环问题的三种解法 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • Python基础教程之异常处理详解

    Python基础教程之异常处理详解 异常处理是程序设计中非常重要的一部分。在Python中,我们可以利用异常机制来处理程序运行过程中出现的错误,使得程序在出错时能够正常运行并记录错误信息,提高程序的健壮性和可维护性。 什么是异常处理 在Python中,异常是程序在运行期间出现的不正常情况,可能导致程序中断或得到错误的结果。异常的产生原因很多,如输入数据不合法…

    C 2023年5月23日
    00
  • c语言实现足球比赛积分统计系统

    使用C语言实现足球比赛积分统计系统 介绍 足球比赛积分统计系统是一个基本的数据管理系统,它能够记录球队之间的胜、负、平等信息,计算出每个球队的比赛积分。本文将详细讲解如何使用C语言实现一个简单的足球比赛积分统计系统。 准备工作 要使用C语言实现足球比赛积分统计系统,您需要了解一些基本的程序设计概念,例如: 变量 运算符 控制结构(如if/else) 循环结构…

    C 2023年5月22日
    00
  • C语言之选择分支语句详解

    C语言之选择分支语句详解 在C语言中,选择分支语句主要用来根据某些条件来决定程序运行的不同路径,通常有以下三种形式: if语句 switch语句 三目运算符 if语句 if语句的一般形式如下: if (条件表达式) { // 条件满足时执行的代码块 } 例如,下面的代码将根据用户输入的数字来判断其是正数、负数还是零: #include <stdio.h…

    C 2023年5月24日
    00
  • Linux折腾记(八):使用GCC和GNU Binutils编写能在x86实模式运行的16位代码

    Linux折腾记(八)的主题是如何使用GCC和GNU Binutils编写能在x86实模式运行的16位代码。针对这个主题,我们可以分为以下几步。 步骤1:准备工作 在开始编写代码之前,我们需要安装在Ubuntu系统上安装GCC和GNU Binutils。可以使用以下命令进行安装: sudo apt-get update sudo apt-get instal…

    C 2023年5月23日
    00
  • spring循环注入异常问题的解决方案

    以下是关于“Spring循环注入异常问题的解决方案”的完整攻略,分为三个部分: 问题分析 在使用Spring框架进行依赖注入的时候,很容易遇到循环依赖的问题,比如A类依赖于B类,而B类又依赖于A类,这种情况下就会出现循环依赖的问题。Spring框架默认是不支持循环依赖的,在出现循环依赖的情况下,Spring会抛出BeanCurrentlyInCreation…

    C 2023年5月23日
    00
  • C语言修炼之路灵根孕育源流出 初识C言大道生上篇

    C语言修炼之路灵根孕育源流出 初识C言大道生上篇 灵根孕育源流出 本篇文章首先介绍了C语言的起源和发展,以及C语言与其他计算机语言之间的关系和区别,为后续学习打下了基础。 初识C言大道生 本篇文章主要介绍了C语言的一些基本概念和语法,包括变量、数据类型、运算符、控制语句等重要内容,让读者初步了解C语言编程的基本思想和方法。 针对本篇文章,下面给出两个示例: …

    C 2023年5月23日
    00
  • c++如何实现归并两个有序链表

    当需要将两个有序链表归并为一个有序链表时,最有效的算法是使用一个指针从头到尾遍历两个链表,并按顺序选择节点,将其添加到新链表。我们可以使用递归或迭代方式实现。 以下是使用c++迭代的实现方法: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { // 判断两个链表是否为空 if(l1 == nullpt…

    C 2023年5月23日
    00
  • C磁盘空间不够用 Win7扩大C盘容量合并磁盘分区的方法

    C磁盘空间不够用 Win7扩大C盘容量合并磁盘分区的方法 在Win7系统中,如果C盘空间不够,需要扩大C盘容量,可以使用系统自带的磁盘管理工具来进行操作。下面我们详细解释如何扩大C盘容量合并磁盘分区。 步骤一:备份数据 在进行磁盘扩容前,必须将数据备份,以免造成数据丢失。用户可以将数据复制到U盘、移动硬盘等外部存储设备上。 步骤二:收缩磁盘 1.打开“计算机…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部