PTA 7-2 约瑟夫环 (25 分)
N个人围成一圈顺序编号,从1号开始按1、2、3......顺序报数,报p者退出圈外,其余的人再从1、2、3开始报数,报p的人再退出圈外,以此类推。 请按退出顺序输出每个退出人的原序号。
输入格式:
输入只有一行,包括一个整数N(1<=N<=3000)及一个整数p(1<=p<=5000)。
输出格式:
按退出顺序输出每个退出人的原序号,数据间以一个空格分隔,但行尾无空格。
输入样例:
在这里给出一组输入。例如:
7 3
输出样例:
3 6 2 7 5 1 4
思路:构建循环链表模拟
#include<stdio.h>
#include<stdlib.h>
#define LEN sizeof(struct Student)
struct Lian_biao
{
int num;
struct Lian_biao *next;
};
struct Lian_biao *create(int N)//创建链表
{
struct Lian_biao *p1,*p2,*head;//定义两个开辟指针和头指针
int n=0;
p1=p2=(struct Lian_biao*)malloc(LEN);//为开辟指针开空间
while(n<N)//输入次数为N
{
n++;
p1->num =n;//把数字存进去
if(n==1)head=p1;//初始把头指针给P1
else p2->next =p1->next ;//之后开始推行,p2要能替代p1,然后p1再去开辟新空间
p2=p1;//next和自己都献身给了p2
p1=(struct Lian_biao*)malloc(LEN);//p1开辟空间
}
p2->next =head;//头尾相接,形成循环链表
free(p1);//释放空间
return head;//返回头指针
}
vvoid print(struct Lian_biao *head,int N,int M)//打印函数,依赖头head和N,三个最重要参数
{
struct Lian_biao *p1,*p2;//双指针上场
int step=0;//计算次数
int n=0;
p2=p1=head;//一开始都赋值头指针
while(p1!=NULL&&N>1)//还有人就打印
{
step++;//报数累加
if(step==M)//如果等于报的数字,则出去
{
N--;//总人数减一
step=1;
n++;
printf("%d ",p1->num );//打印出来
p2->next =p1->next ;//先接上,防止断链表
p2=p1->next ;//如果直接用这个语句,就会断,因为p2->nxet还是指向p1,后面就没了
free(p1);//被删除了,顺便释放
p1=p2;//又让p1指向当前结点
}
p2=p1;//如果没出现踢人的情况,就正常移动,p2在p1后面
p1=p1->next ;//前进搜索
}
printf("%d",p1->num );//打印最后一个
}
int main()
{
int N,M;
scanf("%d%d",&N,&M);//输入
struct Lian_biao *head;
head=create(N);
print(head,N,M);
return 0;
}