题目
分析
按照一般的穷举法,一共有30个开关,所以解空间有 2 30 2^{30} 230个可能,需要减少枚举数目:
如果存在某个局部,一旦这个局部的状态被确定,那么剩余其他部分的状态只能是确定的一种,或者不多的n种,那么就只需枚举这个局部的状态即可
对于本题目,第一行开关按下的状态可以决定剩余所有的状态,将解空间大小缩小为
2
5
2^{5}
25
代码
#include <stdio.h>
int solve(char puzzle[][6], char result[][6]){
int cnt1, cnt2;
for(cnt1 = 1; cnt1 < 5; cnt1++){
for(cnt2 = 0; cnt2 < 6; cnt2++){
if(puzzle[cnt1 - 1][cnt2] == 1){
result[cnt1][cnt2] = 1;
puzzle[cnt1 - 1][cnt2] = !puzzle[cnt1 - 1][cnt2];
puzzle[cnt1][cnt2] = !puzzle[cnt1][cnt2];
if(cnt1+1 < 5) puzzle[cnt1+1][cnt2] = !puzzle[cnt1+1][cnt2];
if(cnt2-1 >= 0) puzzle[cnt1][cnt2-1] = !puzzle[cnt1][cnt2-1];
if(cnt2+1 < 6) puzzle[cnt1][cnt2+1] = !puzzle[cnt1][cnt2+1];
}
else result[cnt1][cnt2] = 0;
}
}
for(cnt2 = 0; cnt2 < 6; cnt2++) if(puzzle[4][cnt2] != 0) return 0;
return 1;
}
int main(){
int puzzleNumber;
char puzzle[5][6];
char puzzleTemp[5][6];
char result[5][6];
int cnt, cnt1, cnt2, cnt3, tmp;
scanf("%d", &puzzleNumber);
for(cnt = 0; cnt < puzzleNumber; cnt++){
for(cnt1 = 0; cnt1 < 5; cnt1++)
for(cnt2 = 0; cnt2 < 6; cnt2++)
scanf("%d", &puzzle[cnt1][cnt2]);
printf("PUZZLE #%d\n", cnt+1);
//枚举,从00000到11111
for(cnt3 = 0; cnt3 < 64; cnt3++){
tmp = cnt3;
//将枚举元分解为第一行的操作
for(cnt2 = 0; cnt2 < 6; cnt2++){
result[0][cnt2] = tmp % 2;
tmp /= 2;
}
//模拟对象初始化
for(cnt1 = 0; cnt1 < 5; cnt1++)
for(cnt2 = 0; cnt2 < 6; cnt2++)
puzzleTemp[cnt1][cnt2] = puzzle[cnt1][cnt2];
//执行第一行操作
for(cnt2 = 0; cnt2 < 6; cnt2++){
if(result[0][cnt2] == 1){
puzzleTemp[0][cnt2] = !puzzleTemp[0][cnt2];
puzzleTemp[1][cnt2] = !puzzleTemp[1][cnt2];
if(cnt2-1 >= 0) puzzleTemp[0][cnt2-1] = !puzzleTemp[0][cnt2-1];
if(cnt2+1 < 6) puzzleTemp[0][cnt2+1] = !puzzleTemp[0][cnt2+1];
}
}
//执行接下来几行的操作,观察是否可以熄灭所有灯
if(solve(puzzleTemp, result))
for(cnt1 = 0; cnt1 < 5; cnt1++)
printf("%d %d %d %d %d %d\n", result[cnt1][0], result[cnt1][1], result[cnt1][2], result[cnt1][3], result[cnt1][4], result[cnt1][5]);
}
}
return 0;
}