美文网首页
题解:报数问题(C++描述)

题解:报数问题(C++描述)

作者: 咸鱼爱学习 | 来源:发表于2020-01-27 14:57 被阅读0次

    题目相关

    题目描述

    有n人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位。

    输入

    初始人数n

    输出

    最后一人的初始编号

    分析

    ​ 在读完题目发现,这道题目就是需要我们模拟循环报数的过程,可以想象一下小时候玩击鼓传花时候的情景。这道题目的难点在于如何判断某个同学是不是还在队伍中,不是简单的判断是否是3的倍数,这种方法,仅适用于不循环的报数,一旦首尾相连,倍数的判断就不太合适了。

    构造数组表明学生的状态

    ​ 每个同学在这道题目中的数据信息有两个,学号(编号),是否在队伍中(在/不在)。如何采用一定的方法,将这两者结合起来则能迅速处理这一问题。此时,我们可以构造一个标记数组,将这两者结合起来。将数组的下标作为学生学号,存储的内容用来表示学生状态。共有两个状态,我们可以使用布尔类型(bool)数组分别用true和false来表示两种状态,也可以使用整数类型数组表示对应状态,为了方便从下标1开始,开辟空间时可开辟人数+1的空间。

    //开辟bool类型数组stu,用来表示各个学生的状态
    //stu[x] 为true 表示报到了3不在队伍中, false 表示还在队伍中
    bool *stu = new bool[n + 1];// n 为学生人数
    

    利用取余实现模拟循环

    ​ 该题的另一个难点在于怎么进行循环?无论是 从1~3反复进行报数还是,n个同学围成一圈,都涉及到了这一点。一种方法是判断,当判断到结尾时,将值重新改成开头。类似下面这样

    if(num==3) num=1;
    if(i==n) i=1;
    
    

    但这么写有些麻烦,也得需要考虑变化过程对他的影响。这事我们可以考虑另一种方法,使用取余符号(%)进行模拟。

    已知%符号的作用是获取余数,例如 7%5=2。当能整除时,结果为0。所以当一个数字%n时,结果一定在0~n-1之间。并且当a%b,a<b时,a%b=a。利用这些特性可以写出这样的一个式子:x=(x+1)%n ,这样x能变成x+1;当x为n-1时,x会变成0,不断重复x就能在0n-1之间循环。若想在1n之间循环可以修改成x=x%n+1。

    int i = 1;      //学生的学号 1~n
    while (ren > 1) //循环报数,直到剩下一个人
    {
        if (stu[i] == false) // 如果在队伍中
        {
            num = num % 3 + 1; //报数
            if (num == 3)
            {                  //报到3
                stu[i] = true; //退出队伍
                ren--;         //在队伍中的人数减一
            }
        }
    
        i = i % n + 1; //下一个学生的编号
    }
    

    枚举法找出最后剩下的人的编号

    最后只剩下最后一人,必定是这样的状态:所有人都是true,只有他是false。那么我们只需要枚举遍历下,找出状态为false的即可。

    for (int j = 1; j <= n; j++)
    {//枚举学号1~n的同学
        if (stu[j] == false)
        {//当状态为false,则说明j在队伍中
            cout << j;//输出编号
            break;//结束循环
        }
    }
    

    代码实现

    #include <iostream>
    #include <cstring>
    using namespace std;
    int main()
    {
        //n-存储人数 num-报的数字 ren-留下的人数
        int n, num = 0, ren; 
        
        cin >> n;            // 输入在人数
        ren = n;             //确定在队伍中的人数
    
        //开辟bool类型数组stu,用来表示各个学生的状态
        //stu[x] 为true 表示报到了3不在队伍中, false 表示还在队伍中
        bool *stu = new bool[n + 1];
    
        //初始化 stu,使初始值为false
        memset(stu, false, sizeof(bool) * (n + 1));
    
        int i = 1;      //学生的学号 1~n
        while (ren > 1) //循环报数,直到剩下一个人
        {
            if (stu[i] == false) // 如果在队伍中
            {
                num = num % 3 + 1; //报数
                if (num == 3)
                {                  //报到3
                    stu[i] = true; //退出队伍
                    ren--;         //在队伍中的人数减一
                }
            }
    
            i = i % n + 1; //下一个学生的编号
        }
    
        for (int j = 1; j <= n; j++)
        {//枚举学号1~n的同学
            if (stu[j] == false)
            {//当状态为false,则说明j在队伍中
                cout << j;//输出编号
                break;//结束循环
            }
        }
    
        return 0;
    }
    
    

    做题时,可从全局角度出发,将题目分解成若干个小问题,解决后再整合起来。通过本题,可以练习数组的构造使用以及循环的处理。

    相关文章

      网友评论

          本文标题:题解:报数问题(C++描述)

          本文链接:https://www.haomeiwen.com/subject/qfkethtx.html