一道简单的模拟题(整数取整)- -> 约瑟夫环问题(持续更新)

文章介绍了约瑟夫环问题及其扩展,包括使用模拟循环链表和队列的方法求解小苹果、围圈报数和玩游戏等问题,提供了详细的解题思路和代码示例。
摘要由CSDN通过智能技术生成

约瑟夫环问题


一、小苹果
题目点击此处跳转: - - > 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(11/3)k=1 可得出 k ≈ 51.1... k\approx51.1... k51.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+b1]


若是题目追加问第 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}] [k3k1]

相关约瑟夫环问题

  1. 圆圈报数
  2. 4400.玩游戏
  3. 招聘

拓展 - > 约瑟夫环问题

一、围圈报数

点击此处跳转题目: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);
  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值