(约瑟夫环)算法训练 筛选号码

本文详细解析了约瑟夫问题的解决方法,采用数组实现,包括编号从1开始及从0开始的不同处理方式,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接给自己写的约瑟夫问题的函数吧!
适用条件:当编号是从1开始,数到m 出局。最后只剩下一个的话。(也就是本题的约瑟夫情况)

int Joseph(int n, int m) {//这里n是总数,m是数到n的人退出,num为最后剩余的人生
    int *Array = new int[n];//动态申请n个单元的数组,每个单元代表一个人
    int k = 0;
    /*当人的编号是从1开始的时候*/
    for (int i = 0; i<n; i++) {
        Array[i] = i + 1;//
    }
    for (int i = n; i > 1; i--) {//最后保留几个人这里的i就大于几
        k = (k + m - 1) % i;//需要退出的人所在数组的下标
        for (int j = k; j < i; j++)
            Array[j] = Array[j + 1];//i=n的时候应该算是越界了
    }
    int result = Array[0];
    delete[] Array;
    return result;
}

这里写图片描述

思路:典型的约瑟夫环问题。
· 这里先简单的写一下本题的解题思路。
· 首先用的是数组进行数据的存储的,输入n个人,就动态的申请n个单元的数组:int *Array = new int[n];
· 然后初始化每一个数组(数组表示的值代表编号)

·这里写一下总结的小公式: int K=0 ;
K=(K+m-1)%i
a[0] a[1] a[2] a[3] a[4] a[5] a[6]………….
1 2 3 4 5 6 7 ………….
1 2 4 5 6 7 ………….
1 2 4 5 7 ………….
1 4 5 7 ………….
1 4 5 ………….
1 4 ………….
1 ………….

K=(0+3-1)%7=2
K=(2+3-1)%6=4
K=(4+3-1)%5=1
K=(1+3-1)%4=3
K=(3+3-1)%3=2
K=(2+3-1)%2=0
上面的K表示的是即将退出的人所在单元的下标这里%的总数是变化的,因为每次出局一个人之后需要将数组重新进行一次调整:用后面单元的内容覆盖前面的内容,同时单元总数相应的减少


也就是:for (int i = n; i>1; i--) {
                            k = (k + 3 - 1) % i;//需要退出的人所在数组的下标
                                for (int j = k; j<i; j++)
                                    Array[j] = Array[j + 1];
                        }
这样第一个for循环的次数为n-1次,最后只剩下0号单元人没退出,输出它的值即可!cout << Array[0] << endl;
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
//int Array[10000];
int main() {
    int n;
        cin >> n;
        int *Array = new int[n];//动态申请n个单元的数组,每个单元代表一个人
    for (int i = 0; i<n; i++) {
        Array[i] = i+1;//
    }
    int k = 0;
    for (int i = n; i>1; i--) {

        k = (k + 3 - 1) % i;//需要退出的人所在数组的下标
        for (int j = k; j<i; j++)
            Array[j] = Array[j + 1];
    }
    cout << Array[0] << endl;
    delete[] Array;
    return 0;
}

好了,用了两个for循环,本题除了用数组去做,也可以考虑用链表去做做!

下面罗列几种约瑟夫问题可能的情况(用数组写的话):
1)就是按照本题的,n个人 ,从1开始编号,数到m的退出,最后就剩下一个

int Joseph(int n, int m) {//这里n是总数,m是数到n的人退出,num为最后剩余的人生
    int *Array = new int[n];//动态申请n个单元的数组,每个单元代表一个人
    int k = 0;
    /*当人的编号是从1开始的时候*/
    for (int i = 0; i<n; i++) {
        Array[i] = i + 1;//
    }
    for (int i = n; i > 1; i--) {//最后保留几个人这里的i就大于几
        k = (k + m - 1) % i;//需要退出的人所在数组的下标
        for (int j = k; j < i; j++)
            Array[j] = Array[j + 1];//i=n的时候应该算是越界了
    }
    int result = Array[0];
    delete[] Array;
    return result;
}

2)如果是从0开始的话:
· 首先数组的下标开始的时候是和编号对应的,但是还是要初始化:
只是公式应该为 int k=0 ;k=(k+m)% i;

int Joseph(int n, int m) {//这里n是总数,m是数到n的人退出,num为最后剩余的人生
    int *Array = new int[n];//动态申请n个单元的数组,每个单元代表一个人
    int k = 0;
    /*当人的编号是从1开始的时候*/
    for (int i = 0; i<n; i++) {
        Array[i] = i ;//
    }
    for (int i = n; i > 1; i--) {//最后保留几个人这里的i就大于几
        k = (k + m) % i;//需要退出的人所在数组的下标
        for (int j = k; j < i; j++)
            Array[j] = Array[j + 1];//i=n的时候应该算是越界了
    }
    int result = Array[0];
    delete[] Array;
    return result;
}

3)最后保留几个数据就在上面两种代码中的

```
for (int i = n; i > 1; i--) {//最后保留几个人这里的i就大于几

i大于1的1改成需要保留的数目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿道学长啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值