问题来历(摘自百度百科):据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
分析:此题采用循环链表来解决此题,把数到3的结点进行删除,然后打印出此结点,最后2个位置就是安全位置。
代码如下:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node* list_init(void) {
struct node *temp;
temp = (struct node*)malloc(sizeof(struct node));
temp->next = NULL;
return temp;
}
void list_add(struct node *L,struct node *new) {
struct node *temp = L;
while (temp->next != NULL) {
temp = temp-> next;
}
temp->next = new;
}
void list_create(struct node *L) {
struct node *temp;
int i;
for(i=1;i<=41;i++) {
temp = (struct node*)malloc(sizeof(struct node));
temp->data=i;
temp->next=NULL;
list_add(L,temp);
}
/*****做成一个循环链表******/
temp = L;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = L->next;
}
void josephus(struct node *L) {
int count=1;
struct node *temp=L->next;
/***这个地方具体详解在下面的图片有补充***/
while (temp->next != temp) {
temp = temp->next;
count++;
if (count == 2) {
count = 1;
printf("%d ",temp->next->data);
temp->next = temp ->next->next;
temp = temp->next;
}
}
printf("%d ",temp->data);
}
int main()
{
struct node *L;
L=list_init();
list_create(L);
josephus(L);
return 0;
}
运行结果:
关于解决约瑟夫问题时可能有以为的地方的补充: