C++经典题目:有n个人围成一圈,顺序排号,然后数数进行淘汰的解法和一些思考...
时间: 2024-03-31 16:35:58 浏览: 59
这道题目可以使用约瑟夫环的经典解法。具体思路如下:
1. 将n个人放入一个循环链表中,编号从1到n。
2. 从第一个人开始,数m个人,将第m个人删除。
3. 从删除的人的下一个人开始重新计数,再数m个人,继续删除。
4. 重复以上步骤,直到链表中只剩下一个人为止。
这个算法的时间复杂度为O(nm),其中n为人数,m为要删除的人数。可以通过动态规划来优化时间复杂度,使其变为O(n)。
具体优化思路如下:
1. 设f(n)为n个人中最后剩下的人的编号。
2. 对于n个人,第一次删除的人的编号为(m-1)%n+1,设为k。
3. 删除k后,剩下的n-1个人中,编号为k+1, k+2, ..., n的人重新排列编号,变为1, 2, ..., n-k。
4. 由于删除了k,所以下一次要从编号为k+1的人开始计数,即从编号为1的人开始计数。所以,下一次删除的人的编号为(m-1)%(n-1)+1。
5. 由于重新编号后,问题转化为n-1个人的问题,所以f(n)=f(n-1)+(m-1)%(n-1)+1。
使用动态规划的思路,时间复杂度可以优化为O(n)。
相关问题
4.有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数), 凡报到3的人退出圈子,问最后留下的是原来第几号的人,用c++实现编写此程序
以下是用 C++ 编写的程序,可以求出最后留下的人原来的编号:
```cpp
#include <iostream>
using namespace std;
int main() {
int n;
cout << "请输入总人数 n:";
cin >> n;
// 初始化数组,表示第 i 个人是否还在圈子里面
bool *in_circle = new bool[n];
for (int i = 0; i < n; i++) {
in_circle[i] = true;
}
int count = 0; // 报数
int left = n; // 剩下的人数
int index = 0; // 当前报数的人的下标
while (left > 1) {
if (in_circle[index]) { // 如果这个人还在圈子里面
count += 1;
if (count == 3) { // 报到 3 了,这个人要退出圈子
in_circle[index] = false;
count = 0;
left -= 1;
}
}
index = (index + 1) % n; // 移动到下一个人
}
// 找到最后留下的人的编号
int result = -1;
for (int i = 0; i < n; i++) {
if (in_circle[i]) {
result = i + 1; // 编号从 1 开始
break;
}
}
cout << "最后留下的人原来的编号是:" << result << endl;
delete[] in_circle; // 释放数组内存
return 0;
}
```
这个程序中用了一个 bool 类型的数组 `in_circle`,表示第 i 个人是否还在圈子里面。一开始,所有人都在圈子里面。每次循环,我们先判断当前报数的人是否还在圈子里面,如果是,我们就让他报数,如果他报到 3 了,就让他退出圈子,并且剩下的人数减 1。最后,我们遍历一遍 `in_circle` 数组,找到最后留下的人的编号。
这个程序的时间复杂度是 O(n^2),因为每次循环都需要遍历整个圈子。如果想要更快的算法,可以使用链表来模拟这个圈子。
有n个人围成一圈顺序排号从第一个人开始,报数从1到3报数,凡报到三的人退出圈子,问最后留下的人原来排在第几号?用指针
是一个经典的约瑟夫问题,可以使用循环链表来解决。具体实现如下:
```c++
#include <iostream>
using namespace std;
struct Node {
int num;
Node* next;
Node(int n) : num(n), next(nullptr) {}
};
int main() {
int n;
cout << "请输入总人数:";
cin >> n;
// 构建循环链表
Node* head = new Node(1);
Node* cur = head;
for (int i = 2; i <= n; i++) {
cur->next = new Node(i);
cur = cur->next;
}
cur->next = head;
// 开始报数
int count = 0;
Node* pre = cur;
cur = head;
while (cur->next != cur) {
count++;
if (count == 3) {
count = 0;
pre->next = cur->next;
delete cur;
cur = pre->next;
} else {
pre = cur;
cur = cur->next;
}
}
// 输出最后留下的人的编号
cout << "最后留下的人的编号是:" << cur->num << endl;
// 释放内存
delete cur;
return 0;
}
```