一、约瑟夫问题的由来
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
二、使用C语言来实现约瑟夫问题,按照自杀的过程打印出自杀的人的序号
下面代码是使用循环链表来实现该功能,很简单的一个问题,详情查看下面代码吧。
/*
* 约瑟夫问题
*/
#include <stdio.h>
#include <stdlib.h>
#define MAX 41
typedef struct link{
int data;
struct link *next;
}*plink;
/* 创建链表 */
void create_link(plink *head, int n)
{
plink p=NULL;
plink node=NULL;
if((*head) == NULL){
(*head) = (plink)malloc(sizeof(struct link));
(*head)->data = n;
(*head)->next = (*head);
return;
}
node=(*head);
while((node->next) != (*head)){
node = node->next;
}
p = (plink)malloc(sizeof(struct link));
p->data = n;
p->next = node->next;
node->next = p;
return;
}
/* 打印链表 */
void print_link(plink head)
{
plink p=NULL;
if(head == NULL){
return;
}
p = head;
printf("%d",p->data);
p = head->next;
while(p != head){
printf("->%d",p->data);
p = p->next;
}
printf("\n");
return;
}
void josepf_link(plink *head)
{
int i=0;
plink p=NULL;
plink pnext=NULL;
if((*head) == NULL){
return;
}
p = (*head);
pnext = p;
while((pnext->next) != pnext){
for(i=0; i<2; i++){
p = pnext;
pnext = p->next;
}
printf("%d->",pnext->data);
p->next = pnext->next;
free(pnext);
pnext = p->next;
}
printf("%d",pnext->data);
free(pnext);
p=NULL;
pnext=NULL;
(*head)=NULL;
return;
}
/* 删除链表 */
void delete_link(plink *head)
{
plink p=NULL;
if((*head) == NULL){
return;
}
p = (*head)->next;
while(p && (p != (*head))){
(*head)->next = p->next;
free(p);
p=(*head)->next;
}
free(p);
(*head)=NULL;
return;
}
int main()
{
int i=0;
int num=0;
plink root=NULL;
srand((unsigned)time(NULL));
for(i=0; i<MAX; i++){
num = rand()%100;
create_link(&root,i+1);
}
print_link(root);
josepf_link(&root);
printf("\n");
delete_link(&root);
return 0;
}