约瑟夫环问题
一、小苹果
题目点击此处跳转: - - > 5307.小苹果
首先来一道简单模拟题, 进而拓展到几个约瑟夫环相关问题, 本文主要采用模拟循环链表法
和队列法
来求解
文章将会持续更新, 一些相关题解和题目也会持续给出, 观众老爷们可以关注一下感谢观看
约瑟夫环问题:
一、围圈报数
点击此处跳转题目:3559.围圈报数
二、玩游戏
题目点击此处跳转:4400.玩游戏
一、小苹果
题目点击此处跳转: - - >5307.小苹果
题目如下:
思路:这里首先观察时间复杂度为
1
e
9
1e9
1e9
若是直接按每个苹果
枚举肯定会TLE
故我们可以想到按天数
来枚举, 那么考虑最坏情况时间复杂度
具体:每天拿走苹果数量为 3 / n 3/n 3/n 的上取整 假设我们需要拿走所有苹果需要
k
天, 则 n ( 1 − 1 / 3 ) k = 1 n(1 - 1/3) ^k = 1 n(1−1/3)k=1 可得出 k ≈ 51.1... k\approx51.1... k≈51.1...
代码如下:
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n;
cin >> n;
int days = 0, date = 0;
while(n) {
days ++;
if(n % 3 == 1 && date == 0) date = days;
n -= (n + 2) / 3; //上取整
// n -= ceil(n / 3); //这样的上取整只适用于float
}
cout << days << " " << date;
return 0;
}
这里上取整的方式, 直接用cmath
库里的ceil()
的话浮点型可能会存在精度问题, 故整数取整
一般采用:
[
a
b
]
=
[
a
+
b
−
1
b
]
[ \frac {a}{b} ] = [ \frac{a + b - 1}{b} ]
[ba]=[ba+b−1]
若是题目追加问第 k 个苹果在第几天被取走, 那么将需要递归递推来解决问题:
1.若是k % 3 == 1, 那么第一天将被拿走, 否则
2.此时 n - - >
2
3
n
\frac{2}{3}n
32n, k - - >
[
k
−
k
−
1
3
]
[k - \frac{k-1}{3}]
[k−3k−1]
相关:约瑟夫环
问题
拓展 - > 约瑟夫环问题
一、围圈报数
点击此处跳转题目:3559.围圈报数
解法一:模拟循环链表求解
#include <iostream>
using namespace std;
const int N = 55;
int ne[N];
int main() {
int t, n;
cin >> t;
while(t --) {
cin >> n;
//初始化环形链表
for(int i = 1; i < n; i++) ne[i] = i + 1;
ne[n] = 1;
int p = n; // 这里假设当前为第n个,则ne[p] = 1, 指向1
for(int i = 0; i < n; i++) { //进行 n次的输出答案
p = ne[ne[p]]; //此操作相当于连走两步停下
cout << ne[p] << " "; //p->ne :第三步即为报号退出者,输出
ne[p] = ne[ne[p]]; //这里进行跳过ne[p]直接指向ne[p]的下一个
}
cout << endl;
}
return 0;
}
解法二:队列求解:
#include <iostream>
#include <queue>
using namespace std;
int n;
queue<int> q;
int main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n;
//将1 - n所有数插入队列中
for (int i = 1; i <= n; i ++) q.push(i);
int cnt = 1
while (!q.empty())
{
if (cnt == 3) //每三个数就将队首弹出重新计数
{
int t = q.front();
q.pop();
cnt = 1;
cout << t << ' '; //输出队头
}
else //反之就是还没有到第三个数
{
int x = q.front();
q.pop();
q.push(x); //队头插到队尾
cnt ++;
}
}
cout << endl;
}
return 0;
}
二、玩游戏
题目点击此处跳转:4400.玩游戏
解法一:队列求解
#include <iostream>
#include <queue>
using namespace std;
queue<int> q;
int main() {
int n, k, a;
cin >> n >> k;
for(int i = 1; i <= n; i++) q.push(i);
while(k --) {
cin >> a;
int t = a % q.size();
while(t--) {
q.push(q.front());
q.pop();
}
cout << q.front() << " ";
q.pop();
}
return 0;
}
解法二:模拟链表求解
#include <iostream>
using namespace std;
int ne[110];
int main() {
int n, k, a;
cin >> n >> k;
for(int i = 1; i < n; i++) ne[i] = i + 1;
ne[n] = 1;
int p = 1;
while(k --) {
cin >> a;
int t = a % n;
if(t == 0) t = n;
while(t-- > 1) p = ne[p];
cout << ne[p] << " ";
ne[p] = ne[ne[p]];
p = ne[p];
n -= 1;
}
return 0;
}
解法三:动态数组vector
vector<int> v;
v.erase(v.begin() + i);