费解的开关 二进制枚举
题目
输入格式
第一行输入正整数 n,代表数据中共有 n 个待解决的游戏初始状态。
以下若干行数据分为 n 组,每组数据有 5 行,每行 5 个字符。
每组数据描述了一个游戏的初始状态。
各组数据间用一个空行分隔。
输出格式
一共输出 n 行数据,每行有一个小于等于 6 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
对于某一个游戏初始状态,若 6 步以内无法使所有灯变亮,则输出 −1。
数据范围
0<n≤500
输入样例:
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
输出样例:
3
2
-1
解题思路
这道题是由1,0来代表灯的开,关,所以一定和位运算有关
我们可以枚举第一行的所有情况(2^5=32),第一行确定后,其实剩余的操作已经固定,只须讲前四行出现0的,由他的下一行去改变它的状态。
最后判断一下最后一行是否全为1,即可知道,这种方案是否可行,然后取32种的最优方案
在进行 二进制枚举的 时候 是对原来的状态 进行操纵 需要用到 备份数组!!!!
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
int n = 5;
char ch[N][N];
char bh[N][N];
int dx[5] = {0,1,0,-1,0};
int dy[5] = {0,0,1,0,-1};
void turn(int x,int y) {
for (int i = 0; i < 5; i ++ ) {
int xx = x + dx[i];
int yy = y + dy[i];
if(xx >= 1 && xx <= n && yy >= 1 && yy <= n) {
ch[xx][yy] ^= 1;
}
}
}
int main () {
int T;
cin >> T;
while (T -- ) {
for (int i = 1; i <= n; i ++ ) cin >> ch[i]+1;
memcpy(bh,ch,sizeof(ch));
int ans = 0x3f3f3f3f;
int f = 0;
for (int op = 1; op <= 32; op ++ ) {
//先判断第一行
int step = 0;
for (int i = 1; i <= n; i ++ ) {
if(op >> (i-1) & 1) {
turn(1,i);
step ++;
}
}
for (int i = 1; i <= n-1; i ++ ) {
for ( int j = 1; j <= n; j ++ ) {
if(ch[i][j] == '0') {
turn(i+1,j);
step ++;
}
}
}
int flag = 1;
for (int i = 1; i <= 5; i ++ ) {
if(ch[n][i] == '0') {
flag = 0;
break;
}
}
if(flag && step <= 6) {
ans = min(ans,step);
f = 1;
}
memcpy(ch,bh,sizeof(ch));
}
if(f == 0) {
puts("-1");
}
else
cout << ans << endl;
}
}