【PTA】7-1 约瑟夫环
题目描述
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
思路
本题使用循环链表模拟围成的圈解决。首先编写CreateList函数实现链表的创建与初始化,并将其定义为循环链表。play函数的功能为寻找到报了m的人输出其序号,并将该结点的后继与其前驱连结(即将该节点删除)。
代码
#include <iostream>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
} * LinkList;
void CreateList(LinkList &L, int n)
{
L = new LNode;
L->next = NULL;
LinkList p = L;
p->data = 1;
for (int i = 1; i < n; i++)
{
p->next = new LNode;
p = p->next;
p->data = i + 1;
p->next = NULL;
}
p->next = L;
}
void play(LinkList &l, int num, int m) //报m者退出圈外
{
LinkList f = l;
while (num)
{
for (int i = 0; i < m - 2; i++)
{
f = f->next;
}
cout << f->next->data;
num--;
if (num != 0)
cout << ' ';
f->next = f->next->next;
f = f->next;
}
}
int main()
{
int N, p;
cin >> N >> p;
if (p == 1)
{
for (int i = 0; i < N; i++)
{
cout << i + 1;
if (i != N - 1)
cout << ' ';
}
return 0;
}
LinkList l;
CreateList(l, N);
play(l, N, p);
return 0;
}
分析总结
在创建链表时将其定义为无头结点的循环链表,目的是在循环报数时方便计数,不会因为头结点的存在导致在经过头结点时对计数进行额外加1的操作,这样在运行时可直接在首元节点处开始计数,可使用for循环进行固定次数的运算,稍微减轻了代码量。