Josephus问题 循环链表

来源:互联网 发布:萤石云软件下载 编辑:程序博客网 时间:2024/05/17 23:12

Josephus问题是下面游戏:N个人从1到N编号,围坐成一个圆圈,从1号开始传递一个热土豆。经过M次传递后拿着热土豆的人被清除离座,围坐人圆圈缩紧,由坐在被清除的人后面拿起热土豆继续进行游戏。最后剩下的人取胜。因此,如果M=0和N=5,那么0到4依次被清除后,5号获胜。同理,M=1和N=5,那么依次被清除的顺序是2,4,1,5

  问题有点像之前碰到的:猴子选大王。之前用数组写,后来发现效率不高,需要的是对清除的数组赋值0;

                                        采用循环链表时,只需删除相应的节点,剩余最后一个节点就是该局获胜的人

#include"stdio.h"
#include"stdlib.h"
#define Error(str) fprintf(stderr,"%s\n",str),exit(1)
#define ElementType int
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
int IsEmpty(List L);
Position Insert(ElementType X,Position P);
Position Find(ElementType X,List L);
void Delete(List L);
List CreateList(void);
void PrintLots(List L,List P);
struct Node
{
ElementType Element;
Position Next;
};
/*
  函数:CreateList()
  功能:创建一个循环链表,首节点为1;
*/
List CreateList(void)
{
   List L;
   L=(List)malloc(sizeof(struct Node));
   if(L==NULL)
  Error("get the position failed!");
   L->Next=L;
   L->Element=1;
   return L;
}
/*
   函数:IsEmpty(L)
   描述:判断链表时候为空;PS其实本例程中不需要此函数,写的时候习惯了
*/
int IsEmpty(List L)
{
return L->Next==L;
}
/*
 函数: Find(X,L)
 描述:X为需要查找的关键字,L为查找的链表
 功能:查找X在L中所在位置
*/
Position Find(ElementType X,List L)
{
Position P;
P=L->Next;
while(P!=NULL&&P->Element!=X)
{
P=P->Next;
P->Element=1;
}
return P;
}
/*
  Insert(X,P)
  描述:X,为需要的链表长度,P为首节点
  功能:根据传递的X,建立相应长为X的循环链表
*/
Position Insert(ElementType X,Position P)

Position Head;
Head=P;
int i=2;
while(i<=X)
{
    Position TmpCell;
TmpCell=(List)malloc(sizeof(struct Node));
if(TmpCell==NULL)
Error("Out of space!");
TmpCell->Element=i;
TmpCell->Next=P->Next;
P->Next=TmpCell;
P=TmpCell;
i++;
}
return Head;
}
/*
 Delete(L)
 功能:删除循环链表;在本例程中,最后只剩一个节点
*/
void DeleteList(List L)
{
List FirstCell;
while(L->Next!=NULL)
{
    FirstCell=L->Next;
   L->Next=FirstCell->Next;
   free(FirstCell);
}
}
/*
  Josephus(num,num_member)
  描述:num为需要循环的次数,相当于问题中的M,num_member为人数,相当于N
*/
void Josephus(ElementType num,ElementType num_member)
{
List L;
L=CreateList();
L=Insert(num_member,L);
 Position HeadL;
 Position Tail;
  Position Precur;
   Position Dele;
   int count=num_member;
   int i;
    HeadL=L;
 while(L->Next!=HeadL)//找到循环链表的尾节点
L=L->Next;
 Tail=L;
 Dele=Tail->Next;
 Precur=Tail;
 while(1)
 {
if(count==1)//使用count作为一个计数器,判断剩余人数
break;
else
{
for(i=0;i<num;i++)
{
Precur=Dele;
Dele=Dele->Next;
}
Precur->Next=Dele->Next;
free(Dele);
Dele=Precur->Next;
--count;
}


 }


   printf("%d",Precur->Element);
}
int main()
{
int a,b;


scanf("%d%d",&a,&b);

Josephus(a,b);
return 0;



}






0 0
原创粉丝点击