7-4 特殊约瑟夫问题
编号为1…N的N个小朋友玩游戏,他们按编号顺时针围成一圈,从第一个人开始按逆时针次序报数,报到第M个人出列;然后再从下个人开始按顺时针次序报数,报到第K个人出列;再从下一个人开始按逆时针次序报数,报到第M个人出列;再从下个人开始按顺时针次序报数,报到第K个人出列……以此类推不断循环,直至最后一人出列。请编写程序按顺序输出出列人的编号。
输入格式:
输入为3个正整数,分别表示N、M、K,均不超过1000。
输出格式:
输出为一行整数,为出列人的编号。每个整数后一个空格。
输入样例:
6 3 5
输出样例:
5 3 1 2 4 6
思路:
1.双向链表结点的设置
typedef struct node {
int data;
struct node *next;
struct node *prior;
} Node, *Link;
2.双向循环链表的删除
因为是双向链表,一个指针其实就可以实现删除,但是为了实现连续删除,如果是顺时针,我用q指针 保存p的next域;如果是逆时针,我用q指针保存p的prior域
完整代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
struct node *prior;
} Node, *Link;
int main() {
int N, M, K;
scanf("%d %d %d", &N, &M, &K);
Link head;
head = (Link)malloc(sizeof(Node));
head->next = head;
head->prior = NULL;
head->data = 1;
if (N == 1) {
printf("1");
return 0;
}
//尾插法建立双向链表
Link p = head;
for (int i = 2; i <= N; i++) {
Link node;
node = (Link)malloc(sizeof(Node));
node->data = i;
node->prior = p;
p->next = node;
node->next = head;
head->prior = node;
p = node;
}
p = head;
Link q = head;
while (p != p->next) { //保证队列里还剩不止一个人
for (int i = 1; i < M; i++)//逆时针的报数
p = p->prior;
q = p->prior;
printf("%d ", p->data);
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
p = q;
for (int i = 1; i < K; i++)//顺时针的报数
p = p->next;
q = p->next;
if (p == p->next)
printf("%d", p->data);
else
printf("%d ", p->data);
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
p = q;
}
if (N % 2 != 0) {//如果N是奇数,那么上面一步后,会还剩余一号
printf("%d", p->data);
free(p);
}
return 0;
}
如果有错误的话欢迎指正^-^!