约瑟夫环
n 个人的编号是 1~n,如果他们依编号按顺时针排成一个圆圈,从编号是1的人开始顺时针报数。
(报数是从1报起)当报到 k 的时候,这个人就退出游戏圈。下一个人重新从1开始报数。
求最后剩下的人的编号。这就是著名的约瑟夫环问题。
本题目就是已知 n,k 的情况下,求最后剩下的人的编号。
题目的输入是一行,2个空格分开的整数n, k
要求输出一个整数,表示最后剩下的人的编号。
约定:0 < n,k < 1百万
例如输入:
10 3
程序应该输出:
4
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
思路1:可以用数组变0去掉赋值给新的数组,然后再继续变0赋给新数组。
当最后剩下的长度为2也就是余一个数的时候,输出即可。
import java.util.Scanner;
/**
* 数组
*/
public class Main {
public static int n,k;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
k = in.nextInt();
int [] a = new int [n+1];
for(int i=1;i<=n;i++){
a[i] = i;
}
dfs(a,0);
}
/**
* 数组变0去掉赋值给新数组
* @param a新的数组
* @param count数到那个数了
*/
private static void dfs(int[] a,int count) {
// TODO Auto-generated method stub
if(a.length<=2){
System.out.println(a[1]);
return;
}
int count1 = 0;
for(int i=1;i<a.length;i++){
if(a[i]!=0){
count++;
if(count==k){
count1++;
a[i] = 0;
count = 0;
}
}
}
int [] b = new int [a.length-count1];
int j = 1;
for(int i=1;i<a.length;i++){
if(a[i]!=0){
b[j] = a[i];
j++;
}
}
dfs(b,count);
}
}
思路2: 可以用list集合,一个一个remove然后下标变动,当余下一个的时候,输出即可。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* list集合
*/
public class test {
public static int n,k;
public static List list = new ArrayList();
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
k = in.nextInt();
for(int i=1;i<=n;i++)
list.add(i);
int temp = 0;
for(int i=0;list.size()!=1;i++){
if(i == list.size())
i = 0;
temp++;
if(temp%k==0){
list.remove(i);
i--;
}
}
System.out.println(list.get(0));
}
}
思路3: 既然是约瑟夫问题,可以用约瑟夫公式。
公式来自优快云 作者:陈浅墨 原文:https://blog.youkuaiyun.com/u011500062/article/details/72855826
import java.util.Scanner;
/**
* 公式
*/
public class test1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
System.out.println(cir(n,k));
}
public static int cir(int n,int m){
int p=0;
for(int i=2;i<=n;i++){
p=(p+m)%i;
}
return p+1;
}
}