枚举--百练2811--熄灯问题
这道题乍一看不会做,但听完老师的思路就变得很简单:
虽然情况很多似乎列举不完,但是我们可以只列举第一行的所有情况,然后推出后面的所有情况,这下这道题就有了思路
我自己写的时候没有用到下面这两句代码(也即在完整代码中高亮标记的那两句)
press[i+1][l]=(press[i-1][l]+press[i][l-1]+press[i][l]+press[i][l+1]+light[i][l])%2; if ((press[5][c-1]+press[5][c]+press[5][c+1]+press[4][c])%2 != puzzle[5][c]);
这两句代码非常巧妙,我感觉算是神来之笔~
另外注意代码中的“首行所有情况枚举”算法,利用二进制数从0加到31得到了第一行的所有0|1情况,非常的巧妙,代码下文有高亮
我自己写的时候写了一个change函数,专门来改变puzzle数组的值,但是这样子做程序得不出结果,原因暂时没有发现..
于是在网上找到了原本代码,经过修改使其简洁得到如下代码:
#include<iostream> #include<algorithm> #include<cmath> #include<cctype> using namespace std; #define puzzle light int light[10][10]={0},press[10][10]={0}; int guess(){ int i,l; for(i=1;i<=4;i++) for(l=1;l<=6;l++){ press[i+1][l]=(press[i-1][l]+press[i][l-1]+press[i][l]+press[i][l+1]+light[i][l])%2; } for(int c=1; c<7; c++) { if ((press[5][c-1]+press[5][c]+press[5][c+1]+press[4][c])%2 != puzzle[5][c]) return 0; } return 1; } int main(){ // freopen("in.txt","r",stdin); int c; for(int i=1;i<=5;i++) for(int l=1;l<=6;l++) scanf("%d",&light[i][l]); for(int i=1;i<=6;i++){ press[1][i]=0; } while(!guess()){ press[1][1]++; c=1; while(press[1][c]>1){ press[1][c]=0; c++; press[1][c]++; } } for(int i=1;i<=5;i++) for(int l=1;l<=6;l++){ if(l!=6) printf("%d ",press[i][l]); else if(i!=5) printf("%d\n",press[i][l]); else printf("%d",press[i][l]); } return 0; }
柳暗花明又一村