上周日参加一个比赛,在线编程里面有一道就是约瑟夫环的问题,当时脑子转不过来弯集合用的arraylist重复的元素不进行覆盖导致循环一直跳不出来。。。。尼玛当时看了将近2个点好生郁闷。其实这个解决思路很简单,就是构建一个循环链表的数据结构,然后判断要杀死的人中间的间隔,while不断判断就OK了
内容要求:
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,问他俩站在那两个位置才能活着留下。并打印出死亡位置
构建环形链表的数据结构:
package 约瑟夫环;
public class MyLinkedList {
//内部类 place用于包裹链表的节点信息 包含当前位置信息 前一个节点和后一个节点
public class Place{
private String place;
private Place before;
private Place after;
public Place(){
}
public Place(String place,Place before,Place after){
this.place = place;
this.before = before;
this.after = after;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public Place getBefore() {
return before;
}
public void setBefore(Place before) {
this.before = before;
}
public Place getAfter() {
return after;
}
public void setAfter(Place after) {
this.after = after;
}
}
public Place header = new Place(null,null,null);
public MyLinkedList(){
header.setBefore(header);
header.setAfter(header);
}
//添加元素的方法
public void add(String value){
Place p = new Place(value,null,null);
p.setAfter(header);
p.setBefore(header.getBefore());
p.getBefore().setAfter(p);
p.getAfter().setBefore(p);
}
//按索引号获得元素
public Place get(int index){
Place result = header;
while(index>0){
if(result.getAfter()!=header){
result = result.getAfter();
index--;
}else{
System.out.println("输入索引超过链表长度或当前链表为空");
System.exit(0);
}
}
return result;
}
//判断元素的长度
public int size(){
int length =0 ;
Place result = header;
while(result.getAfter()!=header){
result = result.getAfter();
length++;
}
return length;
}
//移除当前的节点
public void remove(Place p){
Place before = p.getBefore();
Place after = p.getAfter();
before.setAfter(after);
after.setBefore(before);
p = null;
System.gc();
}
}
具体的内容
package 约瑟夫环;
import 约瑟夫环.MyLinkedList.Place;
public class KillGame {
//引入循环链表
public MyLinkedList mll = new MyLinkedList();
//根据人数初始化链表
public void initList(int number){
for(int i=0;i<number;i++){
mll.add("位置"+(i+1));
}
}
public static void main(String[] args){
KillGame kg = new KillGame();
//初始化了41个人
kg.initList(41);
//计数的标志
int index = 1;
//报数位置 初始的时候指向头
Place p = kg.mll.header;
//开始杀人游戏
while(kg.mll.size()>2){
//假如当前报数位置指向了header节点让其自动移到下一位
if(p == kg.mll.header){
p = p.getAfter();
}
//假如当前计数为报数的第三个人就杀死他
if(index%3==0){
System.out.println(p.getPlace()+"已死亡");
kg.mll.remove(p);
p = p.getAfter();
//否则继续向下进行报数
}else{
p = p.getAfter();
}
//记数号+1
index++;
}
//当前节点为3个时候跳出循环包含两个幸存者和一个header节点
System.out.println();
System.out.println("幸存者所在位置"+kg.mll.get(1).getPlace());
System.out.println("幸存者所在位置"2Bkg.mll.get(2).getPlace());
}
}
欢迎讨论