约瑟夫(Joseph)问题:
编号为1,2,3,……n的n个人按顺时针方向围坐一圈,每个人持有一个密码(正整数),一开始任选一个整数作为报数上限m,从第一个人开始按顺时针方向从自1开始报数,报到m时停止报数。报m的人出列,将他的密码作为新的m的值,从他的顺时针方向上的下一个人开始重新从1报数,从此下去,直到所有人全部出列为止,设计一个程序求出出列/顺序。
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
int code;//编号
int key;//密码
struct Node *next;
}LNode,*LinkList;
void CreatList(LinkList &L,int n);//建立一个循环链表,无头结点,n为人数
void Joseph(LinkList &L,int m);//m为第一次报数上限
int main()
{
LinkList La;
int n,m;//人数,第一次报数上限
scanf("%d%d",&n,&m);
CreatList(La,n);
Joseph(La,m);
return 0;
}
void CreatList(LinkList &L,int n)
{
LinKList p,r;
int i;//记录分配结点个数
L=(LinkList)malloc(sizeof(LNode));//分配首元结点
if(!L)//分配失败,则强制终止程序
exit(-1);
r=L;
L->next=NULL;
L->code=1;
scanf("%d",&L->key);
for(i=2;i<=n;i++)//用尾插法建立链表
{
p=(LinkList)malloc(sizeof(LNode));
if(!L)
exit(-1);
p->code=i;
scanf("%d",&L->key);
r->next=p;
p->next=NULL;
r=p;
}
r->next=L;//循环链表
L=r;//用尾结点表示链表-->因为是从第一个人开始计算
}
void Joseph(LinkList &L,int m)
{
while(L->next!=L)//执行到只有一个结点
{
for(int i=1;i<m;i++)//找到第i-1个结点
L=L->next;
p=L->next;//记录下地i个结点的地址
L->next=p->next;
m=p->key;
free(p);//释放第i个结点的地址
}
printf("%d\n",L->code);
free(L);
}