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;
}