开关灯问题
Description
n盏灯排成一排,从1到n按顺序依次编号。有n个人也从1到n依次编号。第一个人(1号)将灯全部关闭。第二个人(2号)将凡是2和2的倍数的灯打开。第三个人(3号)将凡是3和3的倍数的灯作相反处理(该灯如为打开的将其关闭;如为关闭的,将其打开)。以后的人都和三号一样,将凡是与自己相同的灯和是自己编号倍数的灯作相反处理。请问,当第n个人操作之后,哪几盏灯是点亮的。
Input
共1行。
第1行只有一个整数,即灯的数目n(1≤n≤10000)。
Output
共1行,按从小到大的顺序输出第n个人操作之后还点亮的灯的编号,每两个编号之间用空格隔开。
Sample Input
6
Sample Output
2 3 5 6
Source
习题5-1
?
问题分析:
???????这个题目思路简单,有两种思维方式。一种是基于人的,另外一种是基于灯的。
?????? a.从人入手,将序号每个能整除人的序号的灯的状态改变,如果是关的就打开,否则就关闭;
?????? b.从灯入手,计算每个灯的序号的因子数。如果是奇数,则最后状态为关闭,如果是偶数个因子,则最后的状态为打开。
解决方案:
??????设定一个数组light[10001]来表示灯的状态,可以用1表示打开状态,用0表示关闭状态。
???? ?对于a思路,可以用一个双重循环。外层循环控制人的序号从1~n,内层循环控制灯的序号,也是从1~n。每次都判断一下是否整除,如果整除则改变light的状态,即1变0,0变1。当然,我们还有更好的方法,即直接用人的序号当做步长?,去改变灯的序号的状态。这样可以减少循环的次数。在经过n的循环之后。最后用一个1~n的循环扫描一下light数组,将状态为1的灯的序号打印出来。
?????对于b思路。直接看这个数是不是平方数。只要是平方数,则因子个数为奇数;不是平方数的话,则最终状态肯定是打开的,即为我们的输出。在这种方法的情况下,是不需要对输出进行一个单独的扫描的,边判断边输出即可。
参考程序a:
?
//***************************** //Author:GWL //Date:2010-12-09 //version:1.0 //***************************** #include<stdio.h> int main() { //----------input&&init--------------- int i,n; scanf("%d",&n); int Light[10001]={0}; //0:open 1:close because it's easy to init to 0 //but we had better to init to 1 , it's more meaningful //--------------End------------------- //------------operate----------------- for(i=1;i<=n;i++) { int step = i; //use step to reduce the loop time int now = i; while(now<=n) { if(Light[now]==1){ Light[now]=0; } else{ Light[now]=1; } now = now + step; } //--------------End------------------- //--------------output---------------- for(i=1;i<=n;i++) { if(Light[i]==0) printf("%d ",i); } //--------------End------------------- return 0; }
??
Memory:20K??Time:150MS
Language:GCC??Result:Accepted
?
参考程序b:
//***************************** //Author:GWL //Date:2010-12-09 //version:1.0 //***************************** #include<stdio.h> #include<math.h> int main() { //----------input&&init--------------- int i,n; scanf("%d",&n); int Light[10001]={0}; //0:open 1:close because it's easy to init to 0 //but we had better to init to 1 , it's more meaningful //--------------End------------------- //---------operate&&output------------ for(i=1;i<=n;i++) { int tmp=(int)sqrt(i); if(tmp*tmp!=i) //not k^2 printf("%d ",i); } //--------------End------------------- return 0; }
?
Memory:20K??Time:150MS
Language:GCC??Result:Accepted
常见问题:
??? 1.数组大小申明为10000,导致越界。