Joseph问题(循环链表)

循环链表最著名的应用就是Joseph问题:

Josephu问题:据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人找到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。 如何用循环链表来求解Josephu问题?
View Code
 1 #include <iostream>
 2 using namespace std;
 3 
 4 typedef struct _node{
 5         int data;
 6         struct _node *next;
 7 }node, *pointer, *linklist;
 8 
 9 linklist Create_clist(int n) //创建循环链表 
10 {
11     pointer head,rear;
12     head=new node;
13     rear=head;
14     for(int i=1;i<=n;i++)
15     {
16         pointer s=new node;
17         s->data=i;
18         rear->next=s;
19         rear=s;
20     }
21     rear->next=head;
22     return rear;
23 }
24 
25 void Joseph(linklist clist,int k,int m) //clist:循环链表,k:开始位置,m:步长 
26 {
27      clist->next=clist->next->next;
28      pointer cur=clist,pre;
29      for(int i=1;i<=k;i++)
30      {
31           pre=cur;
32           cur=cur->next;
33      }
34      while(cur!=cur->next)
35      {
36           for(int i=1;i<m;i++)
37           {
38               pre=cur;
39               cur=cur->next;
40           }
41           cout<<"Kill "<<cur->data<<endl;
42           pre->next=cur->next;
43           delete cur;
44           cur=pre->next;
45      }
46      cout<<cur->data<<" survived."<<endl;
47 } 
48 
49 int main()
50 {
51     linklist clist=Create_clist(41);
52     Joseph(clist,1,3);
53     
54     system("pause");
55     return 0;
56 }

joseph

可以看出,Joseph还是给自己留了一手。

ps:招聘时,经常会遇到遇到类似Joseph问题的笔试题,比如国内某视频网站2012.9的笔试题:
有一个单向循环链表队列,从头开始报数,当报到m或者m的倍数的元素出列,根据出列的先后顺序重新组成单向循环链表。函数原型: void reorder(Node **head , int m)

下面给出实现:

View Code
 1 #include <iostream>
 2 #include <iomanip>
 3 using namespace std;
 4 
 5 typedef struct _node{
 6         int data;
 7         struct _node *next;
 8 }node, *pointer, *linklist;
 9 
10 linklist Create_clist(int n)
11 {
12     pointer head,rear;
13     head=new node;
14     rear=head;
15     for(int i=1;i<=n;i++)
16     {
17         pointer s=new node;
18         s->data=i;
19         rear->next=s;
20         rear=s;
21     }
22     rear->next=head;
23     return rear;
24 }
25 
26 void print(linklist clist)
27 {
28     pointer head=clist->next;
29     pointer p=head;
30     while((p=p->next)!=head)
31         cout<<setw(4)<<p->data<<" ";
32     cout<<endl;
33 }
34 
35 void reorder(linklist *p,int m)
36 {
37     pointer head,rear,cur,pre;
38     rear=*p;
39     head=rear->next; //头结点
40     cur=head->next; //cur指向第一个结点
41     rear->next=cur; //为了方便,头结点不参加循环
42     
43     rear=head;
44     while(cur->next!=cur){
45         for(int i=1;i<m;i++)
46         {
47             pre=cur;
48             cur=cur->next;
49         }
50 
51         //出列的结点,按照尾插法重新插入链表
52         rear->next=cur;
53         rear=cur;
54 
55         //跳过出列的结点,继续循环
56         cur=cur->next;
57         pre->next=cur;
58     }
59     rear->next=cur;
60     rear=cur;
61     rear->next=head;
62     
63     *p=rear;
64 }
65 
66 int main()
67 {
68     linklist clist=Create_clist(41);
69     reorder(&clist,3);
70     print(clist);
71     
72     system("pause");
73     return 0;
74 }

joseph_youku

ps: Joseph问题也有相应的数学解法

1 int ret=0;
2 for(int i=2;i<n;i++)
3    ret=(ret+m)%i;

参考http://blog.csdn.net/w57w57w57/article/details/6639194

原文地址:https://www.cnblogs.com/emituofo/p/2766872.html