枚举--百练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;
}

  

posted @ 2018-02-24 20:54  柳暗花明_liu  阅读(183)  评论(0编辑  收藏  举报