题目 2288 蓝桥杯2018年第九届真题 约瑟夫环

目录

题目描述

解题思路

代码实现


题目描述

n 个人的编号是 1~n,如果他们依编号按顺时针排成一个圆圈,从编号是1的人开始顺时针报数。

(报数是从1报起)当报到 k 的时候,这个人就退出游戏圈。下一个人重新从1开始报数。

求最后剩下的人的编号。这就是著名的约瑟夫环问题。


本题目就是已知 n,k 的情况下,求最后剩下的人的编号。

输入格式

题目的输入是一行,2个空格分开的整数n, k

约定:0 < n,k < 1百万

输出格式

要求输出一个整数,表示最后剩下的人的编号。

样例输入

10 3

样例输出

4

解题思路

(事先声明:通过查阅找到约瑟夫环的递推公式,有了这个公式解题可以保证运行不超时。)

先分析一下此约瑟夫问题,此题要求最后剩下的人的编号,实际上就是求最后一个出列(退出游戏)的人的编号。编号从0开始。


首先给出约瑟夫环的递推公式:f(n,m)=[f(n-1)+m]%n ,(n>1)

n表示参与约瑟夫环的总人数,m表示报到数字k的第几人出列。


接下来分析一下公式如何得出的:

利用递归的思想,解决n个人报数需要先解决(n-1)个人报数的问题,解决(n-1)个人报依次数问题需先解决[(n-1)-1]个人报数的问题,依次类推到最初情况应该是n=1,只有1个人的情况。

假设n=1时,可得到f(n,m)=f(1,m)=0 , 因为此时我们可以知道无论m等于多少最后出列的人都是编号为0的人,因为场上只有编号为0的人。

假设n=2,报到数字m的人出列。由于编号从0开始,所以(m-1)号相当于是从第一个报数开始时的第m个人(也就是报到数字m的人)。此时最后出列的人应该是n=1即只有1个人报数时的最后出列的序号加上m。

可得到f(2,m)=f(1)+m

思考到这里,我们还需要考虑所报数字大于剩下的人数的情况,在上面的基础上再假设m=3,计算可得:f(2,m)=f(2,3)=0+3=3,很明显只有两个人,没有编号为3的人。此时我们想由于是环状报数,当2个人报完以后需要从编号为0的人开始接着报数。所以我们可以对所求的f(2,m)的值进行求模运算(即求出在所有人中来回报数后,不足一个轮回了还剩下多少人,剩下的人当中最后必定会报出所报数字m)。

即算式应该为:f(2,m)=f(2,3)=[f(1)+3]%2=[0+3]%2=1

所以最后编号为1的人出列,即最后剩下编号为1的人(可自己手动模拟验证)。

同理当n=3,m=3时,算式为:f(n,m)=f(3,3)=[f(2,3)+3]%3=[1+3]%3=1

所以最后编号为1的人出列,即最后剩下编号为1的人(可自己手动模拟验证)。

同理当n=4,m=3时,算式为:f(n,m)=f(4,3)=[f(3,3)+3]%4=0

......


据此可推导出参与报数的总人数为n时,公式为:f(n,m)=[f(n-1)+m]%n

代码实现

import java.util.Scanner;

public class Main{
    
public static void main(String[]args){
    Scanner sc = new Scanner(System.in);
        while (sc.hasNextInt()) {
            //hasNextInt()方法是判断控制台接收是否为整型数字,而不是接收数据。

            int n=scanner.nextInt();//n表示参与约瑟夫环的总人数
            int m=scanner.nextInt();//m是报到数字k的第几人出列
            int num=0;
            //i表示递归状态中的层次,从i=2开始表示f(2,m),即第二层的总人数为2,依次循环3,4,...,n
            for (int i = 2; i <=n; i++) {//当i=1时即总人数为1个人报数时编号num为0,不参与循环
                num=(num+m)%i;//即计算公式f(n,m)=[f(n-1)+m]%n
            }
            System.out.println(num+1);
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值