Josephus問題 循環鏈表

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;



}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章