约瑟夫问题

题目:

有n个人围成一圈,顺序排号。从第一个人开始报数(从1到m报数),凡报到m的人退出圈子,问最后留下的是原来第几号的那位。

解题思路:

1、阅读题目后可以知道这里涉及到循环,因为不是报数一轮就会停止,而是会一直报数。那么首先要考虑循环的终止条件,通读题目可知,最后只会剩一个人,可以作为循环的终止条件。

以最简单的三个人报数到三淘汰为例,首先编号为3的人会被淘汰,剩余两个人接着报数,编号为1的人第二个被淘汰,最后剩下的人编号为2。当n和m发生变化时,过程类似。

2、在循环中,首先要判断轮到的人有没有被淘汰,没有被淘汰的人才能报数。

报数又分为两种情况:

(1)报数报到m,此人会被淘汰(程序中令其编号归零),报数会从下一个人重新开始(报数统计归零),淘汰人数会加1。

(2)报数没有报到m,轮到下一个人(指针移动)。

3、无论上一个人报数情况如何,都该下一个人进行报数(指针向后移动)。如果移动后指针指向队尾,证明报数了一圈,那么应该重置指针指向队首,开始下一圈。

4、重复2、3过程,直到只有一个人没有被淘汰(唯一编号没有被归零的人),结束循环。

程序代码:

#include <stdio.h>

int main(int argc, char *argv[])
{ 
    int n,m,i = 0;
    int *p = NULL;
    printf("请输入有多少人参与:");
    scanf("%d",&n);
    printf("第几个报数的人会被淘汰:");
    scanf("%d",&m);
    int a[n];
    p = a;
    for(i = 0; i < n; i++){
        a[i] = i+1;//给每个人编号
    }
    i = 0;//重置i的值
    int count_1 = 0,count_2 = 0;//count_1用来记录报数,count_2用来统计淘汰的人
    while(count_2 < n - 1) {//当淘汰的人达到n-1,即只剩最后一人时报数结束
        if(p[i] != 0){//如果没有被淘汰的人就要报数
            count_1++;
           }
        if(count_1 == m){//报到指定数字的人
            count_1 = 0;//淘汰人后应该重新开始报数
            p[i] = 0;//标记淘汰
            count_2++;//记录淘汰人数
        }
        i++;//指向下一个人
        if(i == n){//i只能先自增再判断,只有i++后i才可能得n
            i = 0;//当指向队尾时,需要重置,使其重新指向队首
        }
    }
    printf("最后的人起始编号为:");
    for(i = 0;i < n;i++){
        if(a[i] != 0){
            printf("%d\n",a[i]);
            break;//最后只会剩一个人,当找到第一个人后就可以推出循环
        }
    }

    return 0;
} 

运行结果:

请输入有多少人参与:8
第几个报数的人会被淘汰:3
最后的人起始编号为:7
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值