• 【题目】开灯关灯问题


    题目

    有n(n>0)盏灯,编号为1~n,在桌子上排成一排。开始都是熄灭状态。

    第1趟,按下编号为1 的倍数的 灯的开关。(第一趟后所有的灯都亮了)

    第2趟,按下编号为2 的倍数的 灯的开关。

    ....

    第 i 趟,按下编号为i 的倍数的 灯的开关。

    一直到第n趟,结束。

    :n趟过后,哪些灯亮着,哪些熄灭,有多少亮着?

    根据问题,很直接的写出代码。

    #include<iostream>
    #include<cassert>
    #include<cstring>
    
    using namespace std;
    
    void onoff(size_t n)
    {
        int*door = new int[n+1];
        memset(door, 0, sizeof(int)  * (n + 1));
    
        for (size_t i = 1; i <=n ; i++)       // 走n趟
        {
            for (size_t k = i; k <=n; k+=i)  //比 i 小的数都不用考虑,因为他们不是 i 的倍数、。
            {
    
                if (k%i == 0)                //如果门k 是 i的整数倍,则改变他的状态
                    door[k] = !door[k];
            }
    
        }
    
    
        for (size_t  i = 1; i <=n; i++)
        {
            cout << door[i] << ' ';
        }
    
        delete[] door;
    
    }
    
    
    
    int main()
    {
        for (size_t i = 1; i <= 36; i++)
        {
            cout << "n=" << i<<'	'; 
            onoff(i);
            cout << endl;
        }
        
        
        return 0;
    }

    运行结果

    n=1     1
    n=2     1 0
    n=3     1 0 0
    n=4     1 0 0 1
    n=5     1 0 0 1 0
    n=6     1 0 0 1 0 0
    n=7     1 0 0 1 0 0 0
    n=8     1 0 0 1 0 0 0 0
    n=9     1 0 0 1 0 0 0 0 1
    n=10    1 0 0 1 0 0 0 0 1 0
    n=11    1 0 0 1 0 0 0 0 1 0 0
    n=12    1 0 0 1 0 0 0 0 1 0 0 0
    n=13    1 0 0 1 0 0 0 0 1 0 0 0 0
    n=14    1 0 0 1 0 0 0 0 1 0 0 0 0 0
    n=15    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0
    n=16    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1
    n=17    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0
    n=18    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0
    n=19    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0
    n=20    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0
    n=21    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0
    n=22    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0
    n=23    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0
    n=24    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
    n=25    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1
    n=26    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0
    n=27    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0
    n=28    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0
    n=29    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0
    n=30    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0
    n=31    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
    n=32    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
    n=33    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
    n=34    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
    n=35    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
    n=36    1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1

    分析总结

    仔细分析后,发现,被按偶数次的灯,最后是熄灭的,而被按奇数次的灯,最后是亮的。而且从运行结果中可以看出规律:最后亮的灯,其编号都是完全平方数。第1盏,第4盏,第9盏...

    举几个例子。

    7 = 1 x 7             编号为7,在第1 趟和第 7 趟被按下。


    30 = 1 x 30        编号为30,在1,30 ,2, 15 , 3 , 10 趟都会被按下。
        = 2 x 15
        = 3 x 10

    1 = 1 x 1             编号为1, 在第 1趟被按下

    4 = 1 x 4            编号为4 , 在第1  4  2  趟被按下

       = 2 x 2

    可以发现,编号是完全平方数,就会被按奇数次。否则会按下偶数次。因此,这个题目转而变为判断哪些数是完全平方数了。

    即:编号为完全平方数的灯,最后是亮的,否则就是熄灭的。

    判断一个数是否是完全平方数(不考虑负数)

    bool isPerfectSquare(unsigned int n)
    {
        unsigned int low = (unsigned int)sqrt(n);
    
        return (low*low == n) || ((low + 1)*(low + 1) == n);
    
    
        /*  之所以不直接用 low*low==n判断,是因为浮点数的不精确存储。比如  sqrt(25)在某些时候【可能】会返回4.999999 ,取整后变为4了。  
            因此,以防意外,我们需要再往上增1判断。 || 是满足短路求值的,因此性能不会损失
        
        */
    
    
    }
  • 相关阅读:
    85. Maximal Rectangle
    120. Triangle
    72. Edit Distance
    39. Combination Sum
    44. Wildcard Matching
    138. Copy List with Random Pointer
    91. Decode Ways
    142. Linked List Cycle II
    异或的性质及应用
    64. Minimum Path Sum
  • 原文地址:https://www.cnblogs.com/lulipro/p/6685859.html
Copyright © 2020-2023  润新知