AcWing 4400. 玩游戏

这篇博客讨论了约瑟夫环问题的解决方法,通过两种不同的模拟策略,包括使用数组和队列实现。作者在周赛中首次尝试使用数组模拟,虽然能解决一部分问题,但存在效率问题。在赛后分析中,发现了问题所在并进行了优化,引入了取模运算以避免超时。优化后的代码使用队列进行模拟,简洁且高效。博客强调了在编程解决问题时,代码优化和效率的重要性。
摘要由CSDN通过智能技术生成

题目描述

n 个小朋友围成一圈,玩数数游戏。

小朋友们按顺时针顺序,依次编号为 1∼n。

初始时,1 号小朋友被指定为领头人。

游戏一共会行进 k 轮。

在第 i 轮中,领头人会从他的顺时针方向的下一个人开始,按顺时针顺序数 ai 个人。

其中,最后一个被领头人数到的人被淘汰出局,这也意味着该轮游戏结束。

出局者的顺时针方向的下一个人被指定为新领头人,引领新一轮游戏。

例如,假设当游戏即将开始第 ii 轮时,还剩下 55 个小朋友,编号按顺时针顺序依次为 8,10,13,14,16,并且当前领头人为 1313 号小朋友,ai=12,则第 i 轮游戏结束后,最后一个被数到的小朋友为 16 号小朋友,他将被淘汰出局,并且处于其下一位的第 8 号小朋友将被指定为新领头人。

现在,请你求出每一轮次被淘汰的小朋友的编号。

输入格式

第一行包含两个整数 n,k。

第二行包含 k 个整数 a1,a2,…,ak。

输出格式

一行 k 个整数,其中第 i 个整数表示在第 i 轮中被淘汰的小朋友的编号。

数据范围

前三个测试点满足 2≤n≤10。
所有测试点满足 2≤n≤100,1≤k≤n−1,1≤ai≤1e9。

输入样例1:

7 5
10 4 11 4 1

输出样例1:

4 2 5 6 1

输入样例2:

3 2
2 5

输出样例2:

3 2

题解

约瑟夫环的问题,数据比较小,就直接模拟了 。

周赛的时候用的数组来模拟(一次很笨拙的模拟),思路是用另一个bool数组来判断小朋友是否被淘汰,最后只过了一半的数据。

数组模拟
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int a[N];
bool b[N];
int main()
{
    int n,k;
    cin >> n >> k;
    for(int i = 0;i < k;i ++)scanf("%d",&a[i]);
    for(int i = 0,t = 1;i < k;i ++){
        while(1){
            if(t == n + 1)t = 1; 
            if(!a[i]){while(b[t])t++;b[t] = true;cout << t << " ";break;}
            if(b[t++] == false)a[i]--;
        }
    }
    return 0;
}

赛后数据公开发现只能过一半的样例的原因在于while(b[t])t++;在找下一个还在游戏中的小朋友时没有重置到1。但是这样会超时,只取余数即可。

  修改之后的代码如下,主要加入了一个变量mod用来取模,不然会TLE,每次小朋友减少,mod值减一,并且在找还在游戏中的小朋友时超出n的范围置1。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int a[N];
bool b[N];
int main()
{
    int n,k,mod;
    cin >> n >> k;
    mod = n;
    for(int i = 0;i < k;i ++)scanf("%d",&a[i]);
    for(int i = 0,t = 1;i < k;i ++){
        a[i] %= mod;
        while(1){
            if(t == n + 1)t = 1; 
            if(!a[i]){while(b[t]){t++;if(t == n + 1)t = 1;}b[t] = true;mod--;cout << t << " ";t++;break;}
            if(b[t++] == false)a[i]--;

        }
    }
    return 0;
}

优美的队列模拟

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int main()
{
    int n,k;
    cin >> n >> k;
    queue<int> q;
    for (int i = 1; i <= n; i ++ )q.push(i);
    while(k --){
        int a;
        cin >> a;
        a %= q.size();
        for(int i = 1;i <= a;i ++){
            q.push(q.front());
            q.pop();
        }
        cout << q.front() << ' ';
        q.pop();
    }
    return 0;
}

还需要再努力,更好更快更优美!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值