关于Joseph problem(约瑟夫环)问题的解法汇总

import java.util.ArrayList;
import java.util.List;
/*
 * 约瑟夫环问题:
 * 已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。
 * 从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;
此规律重复下去,直到圆桌周围的人全部出列
 */
public class Joseph {
public static void main(String[] args) {
// TODO Auto-generated method stub
method1(50,10,3);
method2(50,10,3);
method3(50,1,3);
}

/*
* 法一 思路:
*  用list集合实现 链表 循环:  先删除再添加-首元素成功变到尾部,而满足条件的直接删除不添加
*  这样 一直循环到 list.size()==1,即得到答案
*/
public static void method1(int n,int start,int m) {
List<Integer> list = new ArrayList<Integer>();
for(int i = 0;i<n;i++) {
//将 起始报数的编号  放在list集合前面;因为删除操作始终操作最前面的元素
if(start+i>n) 
list.add(start+i-n);
else 
list.add(start+i);
}
//用来记录报数的大小
int num = 0;
while(list.size()>1){
for(int j=0;j<m-1;j++) {
num++;
//不为 m的倍数 就自动 "续接"到 尾部
list.add(list.remove(0));
}
num++;
//为 m的倍数 就删除
System.out.println(list.remove(0));
}
System.out.println("最后的编号为"+list.get(0)+"   最终报数大小为:"+num);
}

/*
* 法二 思路:
* 数组下标即为编号,数组内容用来记录是否被淘汰(boolean),这样还省去了删除操作

*/
public static void method2(int n,int start,int m) {
boolean[] arr= new boolean[n];
for(int i=0;i<arr.length;i++) {
arr[i] = true;// 每个人 初始 都未被淘汰
}
int size = n;// 存储 未被淘汰人数 -用以中止循环
int index = start-1; // 第n个人 的数组下标为 n-1
int count = 0; // 记录每个人报的数
while(size>1) {
if(arr[index]==true) {
count ++; //报数
if(count%m==0) { //被淘汰
arr[index] = false;
size --;//未淘汰总人数 减一
System.out.println(index+1); //编号比数组下标多一
}
}
if(index==arr.length-1) index=0; //防止数组下标越界
else index++;
}
for(int i=0;i<arr.length;i++){
if(arr[i]==true) {
System.out.println("最后一个人编号为:"+(i+1)+" ,报数总大小为:"+count);
}
}
}

/*
* 法三(数学函数 递归实现):
* n个人报数,编号(假设编号从0开始与数组下标重合),每出一个人算一轮
* 第一轮 编号为  (m-1)%n 的人 出去,
* 第二轮编号为 m%n的人报1, 若以m%n的人为起点(0),那么第二轮出去的人编号为  (m-1)%(n-1),那么第二轮出去的人在
* 第一轮的编号为:  (m+(m-1)%(n-1))%n
* 设 最后淘汰的人的编号为  Xn
* 那么 就有  Xn = (m + Xn-1)%n  (※ Xn-1为Xn在上一轮的编号)
* 有了这个递推公式,我们就可以从 最后一轮递推到第 n轮:  
* X2 = (m+X1)%2; //倒数第二轮 n =2 
* 最后一轮只剩下一个人,编号肯定为0,即 X1=0
* 所以我们可以这么写:
* j = 0;  //j为 最终留下来的人,最后一轮编号为0
* for(int i=2;i<=n;i++) //从倒数第二轮开始 
* j=(m+j)%i;
* 最终经过n轮后 j的编号 即为最初的编号
*/
public static void method3(int n,int start,int m) {
int j=0;
for(int i=2;i<n;i++) {  //递归 递推到 第二轮淘汰时的编号;因为第一轮从start开始,所以公式需要作出改变
j=(m+j)%i;
}
//最后留下来的人  在第二轮淘汰时 的坐标  逆推 回第一轮 淘汰时的坐标
//start-1是因为 此题 编号从1开始,原本编号从0开始时 公式为 j=(start+m+j)%n;
j=((start-1)+m+j)%n;
//因为 题目要求 编号从1开始,那么最后答案+1即可
System.out.println("法三答案:"+(++j));
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值