据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏 —— 摘自百度百科《约瑟夫问题》
typedef struct node {
int data ;
struct node *next ;
} node ;
node *create (int ppl);
int main ()
{
int ppl = 41 ; // 可自定义
int dead = 3 ; // 报数报到第几个人就得自杀,可自定义
int i = 1 ; // 计数器
node *target = create(ppl); // 创建循环链表
node *tmp = NULL ; // 临时指针,用于删除链表用
while (target != target->next) // 如果最后只剩一个人,他的下家还是自己,就跳脱循环
{
for (i = 1 ; i < dead-1 ; i++) // 循环一次
{
target = target->next ; // 第二位
}
printf("%d --> ",target->next->data); // 再步进一位,第三位,处死
tmp = target->next ; // 访问第三位,tmp即将被释放
target->next = tmp->next ; // 第二位的下家赋予给第四位
free(tmp) ; // 释放
target = target->next ; // 复位,把第四位作为起始报数人
}
printf("%d\n",target->data); // 打印最后一位,因为它没有进入循环
return 0 ;
}
node *create (int ppl)
{
node *head = NULL ;
head = (node*)malloc(sizeof(node)); // 动态分配空间
node *tmp = head ; // 临时指针
node *add = NULL ; // 新结点指针
int i = 1 ;
while (i <= ppl) // i作为每个成员的编号
{
add = (node *)malloc(sizeof(node)); // 动态分配空间
add->data = i++ ; // i随着步进而作为成员的编号被录入
tmp->next = add ; // 尾插法
tmp = add ;
}
tmp->next = head->next ; // 最后一个结点指向头指针的下家,即编号为1的成员
free(head); // 释放头结点
return tmp->next ; // 返回一个以头结点的下家(即第一个被编号的成员)的链表
}