C语言有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
时间: 2023-12-23 14:07:12 浏览: 45
这是一个经典的约瑟夫问题,可以用循环队列或数学公式进行求解。如果一开始的人数是n,每次报数后,剩下的人数会变成n',则最后留下的人的编号为((3-1)%n'+1)。如果我们用f(n)表示n个人时最后留下的人的编号,则f(n) = (f(n-1) + 3) % n + 1,初始条件为f(1) = 1。因此,可以使用递归或循环来解决这个问题。
相关问题
用c语言有 n 个人围成一圈,顺序排号。从第 1 个人开始报数(从 1 到 3 报数), 凡报到 3 的人退出圈子,问最后留下的是原来第几号的人。
这是一个经典的约瑟夫问题,可以用循环链表来实现。
具体实现如下:
```c
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int num;
struct node* next;
} Node;
int main() {
int n = 10; // 假设有10个人
int k = 3;
Node* head = (Node*)malloc(sizeof(Node));
head->num = 1;
Node* p = head;
for (int i = 2; i <= n; i++) {
Node* q = (Node*)malloc(sizeof(Node));
q->num = i;
p->next = q;
p = q;
}
p->next = head; // 链接成循环链表
Node* pre = p; // pre指向最后一个节点
p = head; // p指向第一个节点
while (p->next != p) {
for (int i = 1; i < k; i++) {
pre = p;
p = p->next;
}
printf("出圈的人是:%d\n", p->num);
pre->next = p->next;
Node* q = p;
p = p->next;
free(q);
}
printf("最后留下的人是:%d\n", p->num);
free(p);
return 0;
}
```
输出结果为:
```
出圈的人是:3
出圈的人是:6
出圈的人是:9
出圈的人是:2
出圈的人是:7
出圈的人是:1
出圈的人是:8
出圈的人是:5
最后留下的人是:4
```
因此,最后留下的人是原来的第4号。
用C语言:有n个人围成一圈,顺序排号。从第1个人开始1—3报数,凡报到3的人退出圈子,问最后留下的是原来第几号的那位
可以使用循环链表来模拟这个过程,每个节点表示一个人,节点中保存该人的编号和是否已经退出圈子的标记。具体实现如下:
```c
#include <stdio.h>
#include <stdlib.h>
// 循环链表节点
typedef struct Node {
int num; // 编号
int out; // 是否已经退出圈子
struct Node* next; // 下一个节点
} Node;
// 初始化循环链表
Node* initList(int n) {
Node* head = (Node*)malloc(sizeof(Node));
head->num = 1;
head->out = 0;
Node* cur = head;
for (int i = 2; i <= n; i++) {
Node* node = (Node*)malloc(sizeof(Node));
node->num = i;
node->out = 0;
cur->next = node;
cur = node;
}
cur->next = head; // 将链表首尾相连,形成循环链表
return head;
}
// 模拟报数过程
int countOff(Node* head, int k) {
Node* cur = head;
int count = 1; // 当前报数的人的编号
while (head->next != head) { // 只要链表中还有两个及以上的节点,就继续报数
if (!cur->out && count % 3 == 0) { // 如果该人还没有退出圈子,并且报数到3了
cur->out = 1; // 标记该人已经退出圈子
k--; // 退出圈子的人数减1
if (k == 0) { // 如果已经退出k个人了,直接返回最后留下的人的编号
return cur->num;
}
}
if (!cur->out) { // 如果该人还没有退出圈子
count++; // 报数加1
}
cur = cur->next; // 移动到下一个节点
}
return head->num; // 最后剩下的一个人的编号
}
int main() {
int n, k;
printf("请输入n和k:");
scanf("%d%d", &n, &k);
Node* head = initList(n);
int num = countOff(head, k);
printf("最后留下的是原来第%d号的那位\n", num);
return 0;
}
```
需要注意的是,循环链表的头结点也要参与报数,因此在 `countOff` 函数中需要用一个变量 `count` 来记录当前报数的人的编号。另外,循环链表中的节点需要在程序结束时释放,以免内存泄漏。
阅读全文