猴子选大王-约瑟夫环两种方法,太妙了。

本文详细解析约瑟夫环问题及猴子选大王问题的算法实现,通过具体示例代码展示了如何利用循环和标记解决这类问题,并提供了一种清晰的思路来寻找最终胜出者。

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

 约瑟夫huan

n个人(0,1,2,3,4...n-1),围成一圈,从编号为k的人开始报数,报数报到m的人出队(报数是1,2,...m这样报的)。下次从出队的人之后开始重新报数,循环往复,当队伍中只剩最后一个人的时候,那个人就是大王。现在,给定n,k,m,
请你求出大王的编号。

输入描述:

输入一行包含三个整数n,k,m

1<=n<=100,1<=k<=n-1,1<=m<=100

输出描述:

输出一个整数

示例1

输入

复制5 1 2

5 1 2

输出

复制3

3

思路: 当你拿到这个题的时候,第一印象是不是和那个猴子选大王 的题目有点类似,的确,但是感觉没另外一个麻烦哈,那么你的思是不是这个样子的 呢?

初始化一个数组且所有的元素都是0 或者其他的相同数字然后开始进行标记了,从k开始,然后到了m的时候就标记一个不同的数值,然后记得一件事情这是一个圈圈,且圈圈的人数是在减少,那么你往前走的时候,当达到某个值的时候,你要重新置零,然后重新再进行标记,这样标记几个循环之后,你就剩下一个了,也就是未被标记的那个数字,这个就是你想求得的,然后再来个循环全部数,加一个if语句,来进行输出那个下标就可以了。如果你是这个思路,请在评论区评论 1111,

其实这个思路是正确的,就是看后边的怎么执行了。如下


#include <iostream>
using namespace std;
#define N 1001
int arr[N] = { 0 };
int main()
{
    int n, k, m;//严格遵守题
    int cnt=0,b=0; //cnt是出局 ,b是标记
    cin >> n >> k >> m;
  
   while(cnt!=n){ //终止条件
       if(k>(n-1)) k=0; //标记位置,也说明其长度不止一个
      if(arr[k]==0) b++; //把循环过得给过掉
       while(b==m){ //如果说到了那个标记的数字
           cnt++;
           b=0;
           arr[k]=1;
       }
       k++;
   }
    for(int i=0;i<=n;i++){//将其不是的都排除掉
        if(arr[i]==0)
             cout<<i-1<<"";
    }
   // cout<<k-1<<"";
    return 0;
}

 //这个是关于猴子选大王的输出版本

n个人围成一圈,顺序排号。从第1个人开始报数 (从1到3报数),凡报到3的人退出圈子,问最后退出的顺序。
比如n为3时
退出圈子的顺序是312  //其实就是猴子选大王,但是要求把每次都的给输出

题解思路分析:

首先将全部的猴子来进行编号从1-----n个猴子

开始调用函数,函数的目的就是去晒全全部的,然后剩下最后一个猴子的作用

!!!!!

因为你的猴子的总数会逐渐的减少,因为当是3的时候那个猴子就会自动的走开

所以你要有一个终止的条件,就是总猴子数目等于减去的猴子总数加一就是只剩下一个猴子了

这个是一个大的循环条件,那么再循环内部怎样的展开呢, (不要忘记有标志位,就是当你的猴子数目等于三的时候还有计算出去的猴子数目,以及确保你的有一个在数数的人,所以就是三个标志位置)

while (a[next] == 0) //这是已经走过的的位置了’
        {
            next++;  // 看下一个位置的猴子
            if (next == n + 1) // 到尾部了,再回到头部
                next = 1;//重新从1走起
        }

 之后要做的就是去将每一圈的3给做上标记然后让其数组的组合数字为 0 然后next继续往后边走,但是这个时候要注意就是当next==n+1的时候记得重新置零 让next=1;同时这个时候让flag=0,但是如果不是三得位置则要next继续走,然后当走到头的时候让他重新置零为 1.

flag++; // 报数号加
        if (flag == 3) // 要出去了
        {cout <<a[next] <<" ";//出圈的人的号码来进行输出
            a[next] = 0; //关于next来对其所在的数组进行标记为0
            next++; //继续走
            if (next == n + 1) //当走到尾巴的时候,来拉回来
                next = 1;
            flag = 0;
            out++;      }
        else{    next++;
            if (next == n + 1)
                next = 1; }} 

猴子选大王输出版本
*记得使用全局数组或者是指针,因为这样才可以来将数组内的值输出,不然数组的值不能传递
*在三个人一组的时候,记得要你的循环要拉回来
#include <iostream>
using namespace std;
void king(int a[], int n);
int a[1000];
int main()
{
    int n, i;
    cin >> n;
    a[0] = 0; // 0号位置没有猴子
    for (i = 1; i <= n; i++)
        a[i] = i;  
    king(a, n); //调用函数
    return 0;
}
void king(int a[], int n)
{
    int out = 0; // 出去了几个
    int flag = 0; // 报数号
    int next = 1; // 下一个
    while (out < n - 1)//当out=n-1时停下来,只剩最后一个猴子,那个就是大王,这也就是停止条件
    {
        while (a[next] == 0)
        {
            next++;  // 看下一个位置的猴子
            if (next == n + 1) // 到尾部了,再回到头部
                next = 1;
        }
        flag++; // 报数号加
        if (flag == 3) // 要出去了
        {
        //   
            cout <<a[next] <<" ";
            a[next] = 0;
            next++;
            if (next == n + 1)
                next = 1;
            flag = 0;
            out++;
        }
        else
        {
            next++;
            if (next == n + 1)
                next = 1;
        }
    }
    int i;
    for (i = 1; i < n + 1; i++)
        if (a[i] != 0) //找到最后一只猴子
            cout<<i << endl; 
}

两个的题其实是一摸一样的,都是来去找三个东西, 记录出去的,一直在走next 还有一个就是flag=3的时候就是要进行标记了,因为这个时候要出去了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

duasong111

请给我一毛钱

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

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

打赏作者

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

抵扣说明:

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

余额充值