又见约瑟夫环:有M个人围坐成一圈, 编号依次从1开始递增直到M,现从编号为1的人开始报数,报到N的人出列,然后再从下一人开始重新报数,报到N的人出列;重复这一过程,直至所有人出列。所有出列的人再次按出列顺序围坐成一圈,并从第1人开始报数,这次为报到K的人出队列,然后再从下一人开始重新报数,报到K的人出列;重复这一过程,直至所有人出列。求最后出列次序。题目输入包括M、N、K三个正整数;N、K可能为1。题目要求按最后出队列顺序输出他们的编号,每个测试用例结果占一行,每个编号占4位。用C语言实现
时间: 2024-03-15 21:45:05 浏览: 96
约瑟夫环问题求解代码code.docx
好的,下面是用 C 语言实现的代码:
```c
#include <stdio.h>
#include <stdlib.h>
// 定义链表结构体
struct Node {
int value;
struct Node *next;
};
// 定义链表节点类型
typedef struct Node Node;
// 创建链表
Node *create_linked_list(int m) {
// 创建第一个节点
Node *head = (Node *)malloc(sizeof(Node));
head->value = 1;
head->next = NULL;
// 创建其它节点
Node *prev = head;
for (int i = 2; i <= m; i++) {
Node *node = (Node *)malloc(sizeof(Node));
node->value = i;
node->next = NULL;
prev->next = node;
prev = node;
}
// 将最后一个节点的 next 指向头节点,形成环
prev->next = head;
return head;
}
// 删除链表节点
Node *delete_node(Node *node) {
// 找到要删除的节点的前一个节点
Node *prev = node;
while (prev->next != node) {
prev = prev->next;
}
// 将前一个节点的 next 指向要删除节点的下一个节点
prev->next = node->next;
// 释放要删除的节点的内存
free(node);
// 返回删除节点后的链表头节点
return prev->next;
}
// 模拟约瑟夫环
int *josephus_circle(int m, int n, int k) {
// 创建链表
Node *head = create_linked_list(m);
// 初始化出列顺序数组
int *out_order = (int *)malloc(m * sizeof(int));
int num_out = 0;
// 当链表不为空时循环
while (num_out < m) {
// 找到要出列的节点
Node *node = head;
for (int i = 1; i < n; i++) {
node = node->next;
}
// 将要出列的节点的值加入出列顺序数组
out_order[num_out++] = node->value;
// 删除要出列的节点,更新链表头节点
head = delete_node(node);
}
// 创建链表
head = create_linked_list(m);
// 重新初始化出列顺序数组
int *new_out_order = (int *)malloc(m * sizeof(int));
num_out = 0;
// 当链表不为空时循环
while (num_out < m) {
// 找到要出列的节点
Node *node = head;
for (int i = 1; i < k; i++) {
node = node->next;
}
// 将要出列的节点的值加入出列顺序数组
new_out_order[num_out++] = node->value;
// 删除要出列的节点,更新链表头节点
head = delete_node(node);
}
// 释放链表内存
Node *node = head;
while (node) {
Node *tmp = node;
node = node->next;
free(tmp);
}
// 合并两次出列顺序数组
for (int i = m-1, j = 0; i >= 0; i--, j++) {
out_order[i] = new_out_order[j];
}
free(new_out_order);
// 返回出列顺序数组
return out_order;
}
// 主函数
int main() {
int m, n, k;
scanf("%d%d%d", &m, &n, &k);
int *out_order = josephus_circle(m, n, k);
// 输出结果
for (int i = 0; i < m; i++) {
printf("%4d", out_order[i]);
if ((i+1) % 10 == 0) {
printf("\n");
}
}
if (m % 10 != 0) {
printf("\n");
}
// 释放内存
free(out_order);
return 0;
}
```
以上代码使用链表来模拟约瑟夫环,时间复杂度为 $O(m^2)$,在 $m$ 很大时效率较低。可以使用数学方法求解,时间复杂度为 $O(m)$,但需要一定的数学知识。
阅读全文