N个人围成一圈顺序编号,从1号开始按1、2、3......顺序报数,报p者退出圈外,其余的人再从1、2、3开始报数,报p的人再退出圈外,以此类推。请按退出顺序输出每个退出人的原序号。
输入格式:
输入只有一行,包括一个整数N(1<=N<=3000)及一个整数p(1<=p<=5000)。
输出格式:
按退出顺序输出每个退出人的原序号,数据间以一个空格分隔,但行尾无空格。
方法一:
不使用结构体和指针解决,创建固定数组,数组序号+1即每个人的编号
#include<stdio.h>
int main() {
int m = 0, n = 0, j = 1, y = 0;
scanf("%d %d", &m, &n);
int peoples[3001] = { 0 };//确定数组最大容量,将所有序号初值赋0,表示未出局
for (int x = 0; y < m; x++) {//当y=m表示所有编号均被打印,则结束循环
if (x == m) {//当x等于最后一个人的下一个编号时,将其替换成第一个编号的人;
x = 0;
}
if (peoples[x]) {//若该编号已经退出,则跳过
continue;
}
//若是满足要求的人,打印其编号,再将其值赋1,表示已退出
if (j % n == 0) {
peoples[x] = 1;
if(y==m-1) printf("%d",x+1);
else printf("%d ", x + 1);
y++;
}
j++;
}
}
此方法有着许多缺陷,例如如此创建数组会浪费空间,且每次遍历都需从0到m,最后下来时间复杂度为O(n^2),所以如此方法不是最优解;
方法二:
使用循环链表解决此问题(在VS上可运行)
#include<stdio.h>
#include<stdlib.h>
//链表创建
typedef struct Node {
int data;
struct Node* next;
}Node, * LNode;
//循环链表添加元素
void addnode(LNode* L, int n) {
LNode p = *L;
for (int x = 0; x < n; x++) {//n为所需元素个数
LNode newnode = (LNode)malloc(sizeof(Node));
newnode->next = NULL;
newnode->data = x + 1;
p->next = newnode;
p = newnode;
}
p->next = (*L)->next;
}
int main() {
LNode T = (LNode)malloc(sizeof(Node));
int n = 0, m = 0, x = 1;
scanf("%d %d", &n, &m);
addnode(&T, n);//调用上方定义的函数
LNode p = T;
LNode q;
//遍历输出每个符合条件的人
while (T->next != NULL) {
if (x == m) {
x = 1;
//打印并删除被选中的编号
q = p->next;
p->next = q->next;
printf("%d ", q->data);
free(q);
}
x++;
p = p->next;
}
}
使用循环链表实现,既解决了空间浪费问题,又降低了时间复杂度,不需要再遍历已退出的元素.