Loading...

搜索小练#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开始搜,默认保证了我们字典序几就是从小到大这样排列的

posted @ 2020-07-23 14:07  Youngore  阅读(54)  评论(0)    收藏  举报