搜索小练#4
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 66, INF = 2147483647;
int n, m, res = INF;
int f[N];
int a[N][N], b[N][N], c[N][N], d[N][N];
inline void work (int x, int y) {
c[x][y] = 1-c[x][y];
c[x+1][y] = 1-c[x+1][y];
c[x-1][y] = 1-c[x-1][y];
c[x][y+1] = 1-c[x][y+1];
c[x][y-1] = 1-c[x][y-1];
}
inline void check() {
memset (b, 0, sizeof b);
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= m; ++ j)
c[i][j] = a[i][j];
for (int i = 1; i <= m; ++ i)
if (f[i])
work (1, i), b[1][i] = 1;
for (int i = 2; i <= n; ++ i)
for (int j = 1; j <= m; ++ j)
if (c[i-1][j])
work (i, j), b[i][j] = 1;
for (int i = 1; i <= m; ++ i)
if (c[n][i])
return;
int nows(0);
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= m; ++ j)
if (b[i][j])
++ nows;
if (nows < res){
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= m; ++ j)
d[i][j] = b[i][j];
res = nows;
}
}
inline void dfs (int x) {
if (x == m+1) {
check();
return;
}
f[x] = 0, dfs(x+1);
f[x] = 1, dfs(x+1);
return;
}
int main () {
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= m; ++ j)
scanf ("%d", &a[i][j]);
dfs (1);
if (res == INF) puts ("IMPOSSIBLE");
else {
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j)
cout << d[i][j] << ' ';
cout << '\n';
}
}
return 0;
}
ps:
今天比较心累 就不想用英文了
因为拼单词还得动脑子
这个题先捋一遍思想吧:
我们枚举第一行的状态,通过第一行来决定以下的一些行数。
thus更新答案
但是这题特别tmd狗
"如果最小解有多个,则输出在字典序意义下最小的那个"
真恶心
先埋下一个坑
因为我还没有搞透彻
"先搜0,再搜1能保证字典序最优"
"check函数是s<ans而不是s<=ans"
"因为先搜到的答案一定字典序比后搜到的字符串优"
"#define 字符串 方案"
"
那么后搜到的方案如何干掉先搜到的方案呢——唯有移动步数比先搜到的少"
\(7.14update\):
Q:为什么从零开始搜,要比从1开始搜 更正确?
A:因为字典序是 0 < 1 并且是
'01111' < '10000'还要比较最高位
所以我们从零开始搜的话,我们只可能是如下的搜索过程:‘00001’-->'00011' --> '00111' --> '.....'默认保证了字典序是从小往大搜的
而后面的方案数 如果想干掉之前的ans就必须满足 移动的步数比ans小(即为总的1的个数没有当前ans的1的个数多)
我们不需要再考虑字典序的问题,因为我们先从0开始搜,默认保证了我们字典序几就是从小到大这样排列的

浙公网安备 33010602011771号