voiddfs(int u, int start){ if (u + n - start < m) { // 剩余数个数是否够 return; } if (u == m + 1) { // 已选购、够 m 个数 for (int i = 1; i <= m; i++) { // 打印 printf("%d ", way[i]); } puts(""); return; } for (int i = start; i <= n; i++) { // 按从小到大的顺序,填入 way[u] = i; dfs(u + 1, i + 1); // 递归,下一位 way[u] = 0; // 复原现场 } }
boolcheck(int a, int c){ longlong b = n * (longlong )c - a * c; // 计算b if (!a || !b || !c) { returnfalse; } // 因为我们要对这个判断是否出现的数组进行修改,但是原数组又不能变化,所以我们额外开一个数组进行使用,这样就可以达到判断且不会改变原数组的目的 memcpy(backup, st, sizeof st); while (b) { int x = b % 10; // 取它的每一位,用来过更新一下用过的数字 b /= 10; // 删掉这个已经被选中的数 if (!x || backup[x]) { returnfalse; } backup[x] = true; } for (int i = 1; i <= 9; i++) { // 遍历一下,判断每个数 if (!backup[i]) { returnfalse; } } returntrue; }
voiddfs_c(int u, int a, int c){ // u表示我们已经用了几个数组 if (u > 9) { // 如果已经把9个数用过了 return; } if (check(a, c)) { // 如果满足要求 ans++; } for (int i = 1; i <= 9; i++) { // 将c枚举一遍1~9 if (!st[i]) { st[i] = true; dfs_c(u + 1, a, c * 10 + i); // 如果这个数没用过,那么我们就把它放在c的后面,继续dfs下一层 st[i] = false; } } }
voiddfs_a(int u, int a){ if (a >= n) { return; } if (a) { // 如果a满足条件 dfs_c(u, a, 0); // 递归一下c } for (int i = 1; i <= 9; i++) { // 枚举一下a if (!st[i]) { st[i] = true; dfs_a(u + 1, a * 10 + i); // 如果这个数没有被用过,那么我们就加上它,并且dfs下一层 st[i] = false; // 恢复现场,回溯 } } }
// 将 (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; } }
intmain(){ int n; cin >> n; while (n--) { for (int i = 0; i < 5; i++) { // 按行输入 cin >> g[i]; } int res = 10; // 这里我们枚举了第一行的32种按法,不用管是亮是灭,把第一行所有情况都按一遍 // 按每种情况的第一行,去遍历接下来的行 // 枚举32种第一行的按法只是可能会减少步数,如果直接从第二行开始答案一定是固定的了,找不到最优解或者可能没有解
for (int op = 0; op < 32; op++) { memcpy(backup, g, sizeof g); // 先备份,好还原进行下一次 int step = 0; for (int i = 0; i < 5; i++) { // 先按一遍第一行(1表示按了,0表示没按) if (op >> i & 1) { // 数字2对应 00010,表示第2个位置的按了一下 step++; // 00010 >> 1 & 1 是1,所以 turn(0, 1)即第一行第二个位置 turn(0, i); } } for (int i = 0; i < 4; i++) { // 在第一行按过后,按2,3,4行 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') { // 如果有关着的,直接break dark = true; break; } } if (!dark) { // 如果最后一行全亮 res = min(res, step); // res取上次res和此次按开关的次数的最小值 } memcpy(g, backup, sizeof g); // 复原 } if (res > 6) { // 如果超过6次 res = -1; } cout << res << endl; } return0; }