蓝桥杯1111-约瑟夫环

题目

设有 n 个人围坐在圆桌周围,现从某个位置 k 上的人开始报数,报数到 m 的人就站出来。下一个人,即原来的第 m+1 个位置上的人,又从 1 开始报数,再报数到 m 的人站出来。依次重复下去,直到全部的人都站出来为止。试设计一个程序求出这 n 个人的出列顺序。

输入输出样例:

示例1

输入:

3 5 8

输出:

3
2
1

解法一:模拟法,模拟循环链表

思路

我们使用一个数组来进行模拟,数组的长度是n(模拟多少个人),对于数组元素的值,用1来标记这个人还在桌子上,用0表示已经离开,所以在创建数组时要把元素都初始化为1。

然后我们需要确定起始位置,起始位置的表达式是:(k%n)-1。(因为我们用的是数组,下标从0开始,所以需要减1)

接下来我们要设置两个变量,一个记录已经出列的人数finished(用来判断结束条件,如果finished+1=n说明就剩下最后一个人了,直接输出并结束程序),一个记录指针现在的位置pos(记录现在谁在报数)。

接下来就用一个for循环来模拟报数,从1开始报数到m,

每次先判断这个数是不是m,

是的话先检查finished+1=n条件是否满足,满足的话说明只剩下最后一个人,直接输出并结束程序,如果finished+1=n不满足,那么就说明还有多个人,那么就把pos位置的人置为0(表示出列),出列之后要把i置为0(因为下一轮又从1开始报数,然后这个地方结束后i还有执行一个i++,所以置0),finished要+1,指针要指向下一个没有出列的位置,用do{}while()来实现。

不是m的话,指针要指向下一个没有出列的位置,还是用do{}while()来实现。

//do{}while()代码
do{
    pos=((pos+1)%n);
}while(carry[pos]==0);

代码

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n=scan.nextInt();
        int k=scan.nextInt();
        int m=scan.nextInt();

        //开一个长度为n的数组,从0开始遍历,设置一个变量来记录报数值,还要有一个变量来记录轮到谁叫号了
        int[] carry=new int[n];
        for(int i=0;i<carry.length;i++){
          carry[i]=1;
        }

        //位置指针,确定起始位置
        int pos=((k)%n)-1;
        //记录叫号个数
        int finished=0;
        //叫号
        for(int i=1;i<=m;i++){
          //排到号了,位置指针上的元素出去
          if(i==m){
            System.out.println(pos+1);
            if(finished==n-1){
              return;
            }else{
              carry[pos]=0;
              do{
                pos=((pos+1)%n);
              }while(carry[pos]==0);
              finished++;
              i=0;
            }
          }else{
              do{
                pos=((pos+1)%n);
              }while(carry[pos]==0);
          }
        }

        scan.close();
    }
}

解法二:JAVA链表来实现

思路

思路跟上边很类似,但是要注意的是,使用链表的话每次出列都会使链表变短,所以每次出列之后n都要执行-1操作,pos也不再需要使用do{}while()来实现。

代码:

import java.util.Scanner;
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        int n = scan.nextInt();//人数
        int k = scan.nextInt();//初始的报数位置
        int m = scan.nextInt();//报数m人后去除
        int pos = (k%n)-1;
        LinkedList linkedlist=new LinkedList();
        for(int i=1;i<=n;i++){
          linkedlist.add(i);
        }

        for(int i=1;i<=m;i++){
          //叫到号了
          if(i==m){
            if(linkedlist.size()==1){
              System.out.println(linkedlist.remove(0));
              return;
            }else{
              System.out.println(linkedlist.remove(pos));
              n--;
              i=0;
            }
          }else{
            pos=(pos+1)%n;
          }
        }
        // System.out.println(linkedlist.get(0));
        scan.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值