约瑟夫问题

约瑟夫问题是一个经典的数学问题,最早由古代历史学家弗拉维奥·约瑟夫斯(Flavius Josephus)提出。问题的描述如下:

有n个人围成一圈,从第一个人开始报数,报到m的人被淘汰出局,然后从下一个人重新开始报数,再次报到m的人被淘汰出局,如此循环,直到最后只剩下一个人,这个人即为胜利者。

例如,假设有10个人(编号为1到10),报数到3的人被淘汰。游戏的进行如下:

1 2 3(淘汰)
4 5 6(淘汰)
7 8 9(淘汰)
10 1 2(淘汰)
4 5 7(淘汰)
10 1 4(淘汰)
5 10 1(淘汰)
4 5 10(淘汰)
4 5(淘汰)

最后剩下的胜利者为编号为4的人。

约瑟夫问题的解决方法有多种,其中一种常见的解决方法是使用循环链表或列表来模拟游戏过程。每次淘汰一个人后,将下一个人作为新的起点,继续进行报数,直到只剩下一个人。这个问题也可以用递归的方式解决。

约瑟夫问题有一些变体,例如报数从1开始,或者每次报数的步长不同。但基本思想和解决方法都是类似的。

问题描述:

小约参与了犹余游戏 , 在这个游戏中最后活下来的人才能获得胜利 .
游戏规则是这样的 , n 个玩家们围成一个圈 , 从第一个玩家开始报数
报到 m 的人被枪毙 , 下一个人接着从 1 开始报数 .
直到最后一个活下来的人获得胜利 .
小约现在开始选编号了 , 已知参与的玩家数量为 n, 被枪毙的数是 m. 小约要选到几号位置才会活下来 .
(1<m<n<100)
设计一个程序 , 输入 n m, 输出最后的胜利者
样例输入 : 10 3
样例输出 : 4
我的代码:
#include<iostream>
using namespace std;

int main() {
    int n, m; // 声明整数变量n和m,用于存储输入的值
    cout << "输入n和m:\n"; // 提示用户输入n和m的值
    cin >> n >> m; // 从标准输入读取n和m的值

    int *a = new int[n]; // 动态分配一个整数数组a,大小为n
    int *b = new int[m - 1]; // 动态分配一个整数数组b,大小为m-1

    // 初始化数组a的元素为1到n的连续整数
    for (int i = 0; i < n; i++) {
        a[i] = i + 1;
    }

    int k = n; // 声明整数变量k,用于跟踪当前数组a的大小

    // 模拟游戏,直到数组a中的元素个数小于m,也就是只剩下m-1个元素
    while (k >= m) {
        for (int i = m - 1; i < k - 1; i++) {
            a[i] = a[i + 1]; // 向前移动数组a的元素
        }
        a[k - 1] = 0; // 最后一个元素设为0
        k--; // 减小数组a的大小

        // 将数组a的前m-1个元素复制到数组b
        for (int i = 0; i < m - 1; i++) {
            b[i] = a[i];
        }

        // 将数组a中剩余的元素向前移动m-1个位置
        for (int i = 0; i <= k - m; i++) {
            a[i] = a[i + m - 1];
        }

        // 将数组b的元素放回数组a的末尾
        for (int i = 0; i < m - 1; i++) {
            a[i + k - m + 1] = b[i];
        }
    }

    int o = m; // 声明整数变量o,用于保存初始m的值

    // 再次模拟游戏,直到数组a中只剩下一个元素
    while (k > 1) {
        m = o % k; // 计算新的m值(取模操作)

        // 同样的操作:移动、清零、复制、移动
        for (int i = m - 1; i < k - 1; i++) {
            a[i] = a[i + 1];
        }
        a[k - 1] = 0;
        k--;
        for (int i = 0; i < m - 1; i++) {
            b[i] = a[i];
        }
        for (int i = 0; i <= k - m; i++) {
            a[i] = a[i + m - 1];
        }
        for (int i = 0; i < m - 1; i++) {
            a[i + k - m + 1] = b[i];
        }
    }

    cout << "最后的胜利者:\n";
    cout << a[0]; // 输出最后剩下的胜利者的值

    delete[] a; // 释放动态分配的数组a的内存
    delete[] b; // 释放动态分配的数组b的内存

    return 0; // 返回0表示程序成功执行
}

这段代码是使用C++编写的,实现了解决约瑟夫问题的算法。它使用了两个动态数组a和b来存储玩家编号,并通过循环和移动数组元素的方式模拟游戏过程。代码中的注释解释了每个步骤的作用和意义。最后,输出的结果是最后剩下的胜利者的编号。

下面是迭代的方式:

#include <iostream>
using namespace std;

// 约瑟夫问题的解法
int josephus(int n, int m) {
    int survivor = 0;
    for (int i = 2; i <= n; ++i) {
        survivor = (survivor + m) % i;
    }
    return survivor + 1; // 加1是因为问题使用了1-based indexing
}

int main() {
    int n, m;
    cout << "请输入n和m:";
    cin >> n >> m;
    
    int winner = josephus(n, m);
    cout << "最后的胜利者位置为:" << winner << endl;
    
    return 0;
}

这段代码使用了迭代的方法来解决约瑟夫问题。具体做法是,从第一个人开始,每次数m个人,然后将数到的第m个人淘汰,继续从下一个人开始数。重复这个过程,直到只剩下一个人为止,这个人就是最后的胜利者。

代码中的函数josephus实现了这个算法,它使用一个循环来模拟每轮淘汰的过程。循环的次数是n-1,表示共进行了n-1轮淘汰。在每一轮中,通过 survivor = (survivor + m) % i 来计算下一个要淘汰的人的位置。最后,返回的survivor + 1表示最后的胜利者的位置,加1是因为问题使用了1-based indexing。

main函数中,首先输入n和m的值,然后调用josephus函数来计算最后的胜利者的位置,并将结果输出。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值