班级活动中,一个班n人围成一圈玩游戏时,从某一个人开始数数,当数到m的那个人必须表演一个节目,同时这个人退出游戏。如何安排位置,能使自己避免表演节目呢? 此类问题与约瑟夫问题是同一类问题。
有名的约瑟夫问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=5,M=2,被杀掉的人的序号为2,4,1,5;最后只留下3。
此类问题都可以用单循环链表给以解决。结点包含当前的序号和指向下一序号(或者说结点)的指针。建好整个单循环链表后,从头结点开始遍历,同时开始计数(Count=1开始),当Count=m-1时,删除第m个结点(即序号为m的结点将会受到惩罚)。循环最终只余下一个结点。
本文参考http://blog.csdn.net/createchance/article/details/17426469博客进一步给出详细的理解。
第一步,建立单循环链表
typedef struct node
{
int data;
struct node *next;
}node,*pNode;
pNode List_init(int n)
{
int i;
pNode temp;
pNode head = InsertNode(1);
for(i =n; i>1; i--)
{
temp = InsertNode(i);
temp->next = head->next;
head->next = temp;
}
return head;
}
pNode InsertNode(int n)
{
pNode p = NULL;
p = (pNode)malloc(sizeof(pNode));
p->data = n;
p->next = p;
return p;
}
本文以N=5为例,上述代码实现如下单循环链表
第二步,从list(文中为编号为1的结点)开始,开始计数。当Count=m-1时,删除第m个结点(即序号为m的结点将会受到惩罚)。代码如下
pNode List_begin(pNode list,int m)
{
int count;
pNode temp = NULL;
for(count=1;list->next!=list;count++)
{
if(count == m-1)
{
temp = list->next;
list->next = temp->next;
count = 0;
List_show(list);
}
list = list->next;
}
return list;
}
void List_show(pNode list)
{
pNode p = list;
if(list == NULL)
{
exit(-1);
}
do
{
printf("%3d",p->data);
p = p->next;
}while(list!= p);
printf("\n");
}
当N=5,M=3时,m-1=2
当第一次count=2时,此时list指向序号为2的结点,删除序号为3的结点(到序号为3的结点时,计数值count必为3),删掉后遍历链表,输出值为
2,4,5,1
而后情况类似。