题目

题目描述

有n盏灯,编号为1~n。第1个人把所有灯打开,第2个人按下所有编号为2的倍数的开关(这些灯将被关掉),第3个人按下所有编号为3的倍数的开关(其中关掉的灯将被打开,开着的灯将被关闭),依此类推。一共有k个人,问最后有哪些灯开着?输入n和k,输出开着的灯的编号。k≤n≤1000。

样例输入:

7 3

样例输出:

1 5 6 7

解答

#include<iostream>
using namespace std;

int main()
{
    /*
    1:开
    0:关
    */
    int n = 0, k = 0;
    cin >> n >> k;
    const int MAX = n;
    int a[MAX];

    for (int z = 0; z <= n - 1; z++)
    {
        //生成一个全是1的列表
        a[z] = 1;
    }

    for (int j = 0; j < n; j++)
    {
        for (int i = 1; i <= k; i++)
        {
            if (j % i == 0)
            {
                if (a[j] == 0)
                {
                    a[j] = 1;
                }
                if (a[j] == 1)
                {
                    a[j] = 0;
                }
            }
        }
        if (a[j] == 1)
        {
            cout << j << " ";
        }
    }
    return 0;
}

这个程序当然不能运行,它存在以下问题:

  1. 数组 a[MAX] 未正确初始化,可以改用vector。

  2. a 数组下标从 0 开始,但灯的编号从 1 开始,需要修正数组访问方式

  3. 状态翻转逻辑错误,在翻转灯的状态时,不需要额外判断 a[j] == 0 或 a[j] == 1,直接 a[j] = !a[j]; 即可。

  4. 输出错误,在输出时,遍历 j 是 0 开始的,而灯的编号是 1~n,因此 cout « j; 需要 +1。

修正一下,顺便优化一下,就得到以下代码:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    int n, k;
    cin >> n >> k;
    
    vector<int> a(n + 1, 1); // 用1表示灯最开始是开的

    for (int i = 2; i <= k; i++)  // 从第2个人开始操作
    {
        for (int j = i; j <= n; j += i) // 每 i 个倍数翻转一次
        {
            a[j] = !a[j];  // 翻转状态
        }
    }

    for (int i = 1; i <= n; i++)
    {
        if (a[i] == 1)
        {
            cout << i << " ";
        }
    }
    return 0;
}

这就对了!