约瑟夫环问题描述
m个人围坐一圈,每人持有一个数字,从第一个人开始从1报数,报到n(第一轮n任意给定)的人出圈,将n改为这个出圈的人所持有的数字,下个人开始从1报数,继续报到n的人出列;依次类推直到所有人出圈。
C语言模拟该过程算法
这里采用带有尾结点的循环单向链表存储玩家信息,p和pre两个指针分别指向报数结点和该结点的直接前驱,并同步移动n-1次,删除p指向的结点直至链表为空即可。
具体代码
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int id;//玩家编号
int pw;//玩家持有的数字
struct node *next;
}node,*LinkList;
/*
用带头结点的尾插法创建有n个结点的循环链表,并返回尾结点
*/
LinkList CreateList(LinkList head,int n){
head->next = NULL;//头结点
head->id = 0;
node *r = head;//工作指针,跟随最后一个结点
for(int i=0;i<n;i++){
node *S = (node*)malloc(sizeof(node));
S->id = i+1;
printf("input player%d's password:\n",i+1);
scanf("%d",&S->pw);
r->next = S;
r = S;
}
r->next = head->next;//最后一个结点指向头结点;
return r;
}
void play(LinkList tail,int sum,int pw){
if(sum<1) return;
else{
LinkList pre = tail;
LinkList p = tail->next;
int n = (pw%sum==0)?sum:pw%sum;//一轮中最少步数
while(--n){
pre = p;
p = p->next;
}
pre->next = p->next;
int newPw = p->pw;
printf("player%d out!\n",p->id);
p = p->next;
play(pre,--sum,newPw);
}
}
void main(){
printf("input sum:\n");
int sum ;
scanf("%d",&sum);
LinkList tail = CreateList((LinkList)malloc(sizeof(node)),sum);
printf("input initPW:\n");
int pw ;
scanf("%d",&pw);
play(tail,sum,pw);
}