搜索小练#4

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#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开始搜,默认保证了我们字典序几就是从小到大这样排列的