题目:
约瑟夫环问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。试设计一个程序求出出列顺序。
代码:
//利用单向循环链表模拟此过程,按照出列的顺序印出各人的编号。
#include<stdio.h>
typedef int elemtype;
int n;
typedef struct lnode{
elemtype num; //编号
elemtype code; //密码
struct lnode *next; //指向下一个结点的指针
}lnode;
void Createlist(lnode *L,lnode *&r){
int code;
lnode *p=NULL;
scanf("%d%d",&n,&code);
L->num=1;
L->code=code;
L->next=L;
for(int i=2;i<=n;i++){
p=new lnode;
scanf("%d",&code);
p->num=i;
p->code=code;
p->next=L;
r->next=p;
r=p; //r指向终端结点
}
}
int main(){
int m;
lnode *L=new lnode;
lnode *r=L; //r指向首元结点
lnode *p=NULL; //p为临时保存被删结点的地址以备释放
Createlist(L,r); //建立不带头结点的单向循环链表
scanf("%d",&m); //输入报数上限值m
n--;
while(n--){
for(int i=1;i<m;i++){ //查找目标结点的前驱结点
r=r->next;
}
p=r->next; //p指向要删除的结点
printf("%d ",p->num);
m=p->code;
r->next=p->next;
delete p; //释放删除结点的空间
}
printf("%d\n",r->num);
return 0;
}
//用顺序表实现该问题。
#include<stdio.h>
typedef struct sqlist{
int code; //密码
int flag; //出列标识
}sqlist;
void creatlist(sqlist *&L,int n){
int code;
for(int i=0;i<n;i++){
scanf("%d",&code);
L[i].code=code;
L[i].flag=0; //出列标识初始化为0
}
}
int main(){
int n,m;
scanf("%d",&n);
sqlist *L=new sqlist[n]; //申请数组空间
creatlist(L,n);
scanf("%d",&m);
int i=-1,cnt=n;
while(cnt--){
//未出列人数只剩一个时,只需报数一次
if(cnt==0)m=1;
while(m--){
i++;
//下标i到顺序表末尾,重新回到0下标
if(i%n==0)i=0;
//跳过已标识为出列的下标
while(L[i].flag==1){
i++;
if(i%n==0)i=0;
}
}
printf("%d",i+1);
if(cnt>0)printf(" ");
L[i].flag=1; //出列标识置为1
m=L[i].code; //出列人的密码作为新的m值
}
return 0;
}