【Openjudge, NOI, 枚举】1813熄灯问题

已知灯的情况。

枚举第一行开关的情况。

我们知道这么一种现象:上一行的灯可以由下一行的开关控制达到完全关闭的状态。

更进一步的我们确定这么一种现象:如果知道(1)第n行灯的情况,(2)第n-1行开关的状态,(3)第n行开关的状态。那么,如果想要让第n行的灯全部关闭,第n+1行的开关的状态是确定的。特殊的,第一行只需要知道本行的灯的情况和本行开关的状态。

所以,只需要枚举第一行开关的情况,然后更新灯的状态,之后,通过第一行灯的状态,更新第二行的开关,直到更新到最后一行的开关,此时,如果最后一行的灯也全部是灭掉的状态,即是我们所求的开关的情况。

代码中,用一个整数的低6位表示一行灯或者一行开关。

#include
#include
#include
using namespace std;

void set(int &l, int &s){
	s = l;
}
void change(int &l, int &s, int pos){
	// pos:0,灯和开关不在同一行;1:灯和开关在同一行;
	if (pos == 0){
		l = l ^ s;
	}
	if (pos == 1){
		int left, right, mid;
		left = s << 1;
		right = s >> 1;
		mid = s;
		mid = (left ^ right ^ mid) & 63;
		l = mid ^ l;
	}
}
void show(int *t){
	int i,j;
	for (i = 0; i < 5; i ++){
		for (j = 0; j < 6; j ++){
			cout << ( (t[i] >> j)& 1) << ' ';
		}
		cout << endl;
	}
}

int main()
{
	int lt[5] = {};
	int sw[5] = {};
	int i, j;
	int t;
	for (i = 0 ; i < 5; i ++){
		for (j = 0; j < 6; j ++){
			scanf("%d", &t);
			lt[i] += t << j;
		}
	}
	//枚举第一行开关的状态
	for (sw[0] = 0; sw[0] < 64; sw[0] ++){
		int tsw[5] = {};
		memcpy(tsw, sw, sizeof(sw));
		int tlt[5] = {};
		memcpy(tlt, lt, sizeof(lt));

		change(tlt[0], tsw[0], 1);
		change(tlt[1], tsw[0], 0);

		//根据第一行开关设定每一行开关
		for (i = 1; i < 5; i ++){
			set(tlt[i - 1], tsw[i]);
			change(tlt[i - 1], tsw[i], 0);
			change(tlt[i], tsw[i], 1);
			if (i != 4)
				change(tlt[i + 1], tsw[i], 0);
		}
		if (tlt[4] == 0){
			show(tsw);
			break;
		}
	}
	return 0;
}

你可能感兴趣的:(Openjudge,NOI,枚举)