下班到家后,看到CSDN上一篇关于约瑟夫问题的讨论,然后本人的小宇宙也耐不住了,要知道大学时算法问题曾难住过我,于是本人迅速打开eclipse开写,以下是实现部分:
/**
* 约瑟夫问题编码解答
*/
public class JosephusMain {
public static void main(String[] args) {
int m = 120; //总数为m
int k = 67; //第一次从第k个开始数
int n = 28; //每次都要从1到n,第n个数出列
LinkItem first = new LinkItem(1, null);
LinkItem end = initLink(first, m);
end.next = first;
System.out.println("data is ready: " + first.toString() + "&" + end.toString() + "\n");
calculate(getk(first, k), n);
}
/**
* 初始化链表
*
* @param item
* @param count 链表长度
* @return 返回末端链表元素
*/
private static LinkItem initLink(LinkItem item, int count) {
if (item.value == count) {
return item;
}
item.next = new LinkItem(item.value + 1, null);
return initLink(item.next, count);
}
/**
* 获取从first开始的第k个值
*
* @param first
* @param k
* @return 返回第k个值
*/
private static LinkItem getk(LinkItem first, int k) {
LinkItem itemK = first;
int index = 1;
while (index < k) {
itemK = itemK.next;
index++;
}
return itemK;
}
/**
* 约瑟夫环实现
*
* @param first
* @param n
*/
private static void calculate(LinkItem first, int n) {
LinkItem last = getk(first, n - 1);
LinkItem delete = last.next;
System.out.println(delete.toString());
if (last == delete) {
return;
}
last.next = delete.next;
calculate(last.next, n);
}
}
public class LinkItem {
public int value;
public LinkItem next;
public LinkItem(int value, LinkItem next) {
this.next = next;
this.value = value;
}
@Override
public String toString() {
return "LinkItem{" +
"value=" + value +
'}';
}
}
应用:17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。
这个问题的解法是先算出30人的出列顺序,然后在前15个出列的位置上分别站上一个位非教徒,这算是逆向思路求解啦。