// 这个操作是把(x, y)以及上下左右的灯都变成相反的颜色 voidturn(int x, int y)// 通过坐标偏移量实现 { for (int i = 0; i < 5; i ++ ) { int a = x + dx[i], b = y + dy[i]; //如果在边界外边,直接忽略即可 if (a < 0 || a >= 5 || b < 0 || b >= 5) continue; g[a][b] ^= 1; //异或,值不同时结果为1,相同为0 // '0'是48 所以 ^1就是49 =='1' // '0'对应十进制48,110000(2),110000 ^ 000001 = 110001(对应十进制49,'1') // '0'^1 = '1','1'^1='0' } }
intmain() { int n; scanf("%d", &n); while(n -- ) { // 按行输入,把每一行当成一个字符串 for (int i = 0; i < 5; i ++ ) cin >> g[i]; int res = 10; // 因为后面要取min,所以res赋一个非法且较大的数 // 这里我们枚举了第一行的32种按法,不用管是亮是灭,把第一行所有情况都按一遍 // 按每种情况的第一行,去遍历接下来的行 for (int op = 0; op < 32; op ++ ) { // 我在对这种情况操作的时候,得先备用一下 // 把原始数组备份一下,然后操作g,操作完了还原,然后再操作 memcpy(backup, g, sizeof g); int step = 0; // 第一行的按法(在这里 1 表示按了, 0 表示不按),这里只是为了输出第一行按完之后的状态 for (int i = 0; i < 5; i ++ ) if (op >> i & 1) // 取op对应二进制数的第i位数字 // 00010 >> 1 & 1 是1 所以turn(0, 1) 就是第一行第二个位置 { // 数字3 对应了00011 表示第1 和第2个位置的按一下 step ++ ; turn (0, i); } // 然后通过第一行按完之后的状态,按234行 for (int i =0; i < 4; i ++ )// 枚举行数 for (int j = 0; j < 5;j ++ )// 枚举每行的灯 if (g[i][j] == '0') { step ++; turn (i + 1, j); // 如果这个位置是灭的,就按下一行对应的位置 } bool dark = false; for (int j = 0; j < 5; j ++ ) if (g[4][j] == '0')// 判断最后一行的灯,如果至少有一个暗就无解 { dark = true; break; }
// 对于32种情况的这一种,如果所有的全亮就记录下步数(事实上只记录了最后一行是否dark) if (!dark) res = min(res, step); memcpy (g, backup, sizeof g); } if(res > 6) res = -1; cout << res << endl; } return0; }
// 2021.12.16 新写法,易于理解 #include<iostream> #include<algorithm> #include<cstring> usingnamespacestd; int g[6][6],backup[6][6]; int dx[] = {0,0,1,-1},dy[] = {1,-1,0,0};
voidchange(int x,int y){ g[x][y] = !g[x][y]; for (int i = 0;i < 4;i ++){ int l = x + dx[i],r = y + dy[i]; if (l >= 1 && l <= 5 && r >= 1 && r <= 5){ g[l][r] = !g[l][r]; } } }
intcal(){ int ans = 10; for (int op = 0;op < 32;op ++){ int res = 0; memcpy(backup,g,sizeof g); // 保存现场 for (int i = 0;i < 5;i ++){ if (op >> i & 1){ change(1,i+1); res ++; } } for (int i = 1;i <= 4;i ++){ for (int j = 1;j <= 5;j ++){ if (!g[i][j]){ change(i+1,j); res++; } } } bool flag = true; for (int i = 1;i <= 5;i ++){ if (!g[5][i]){ flag = false;break; } } if (flag) ans = min(res,ans); memcpy(g,backup,sizeof g); // 恢复现场 } if (ans > 6) return-1; elsereturn ans; }
intmain(){ int n; cin >> n; while (n--){ char str[5]; for (int i = 1;i <= 5;i ++){ cin >> str; for (int j = 1;j <= 5;j ++){ g[i][j] = str[j-1] - '0'; } } cout << cal() << '\n'; } return0; }