poj 3279(状态压缩的搜索)

题目
题意:给一个仅由0,1组成nm的矩阵,每次操作可以反转一个单元格(把0变成1,1变成0),同时这个单元格上下左右的所有格子也会反转,求出把整个矩阵都变成0所需的做小操作次数,不可能的话输出-1
思路:力扣上有一道很类似的题:转化为全零矩阵的最少反转次数
这个唯一的区别就是要记录一下路径;
其实我一点没看出来这是个搜索,求抵达某一状态的最小操作数,讲道理广搜是可以做,就是状态的保存不经过处理的话,就只能存矩阵,那就可能会炸内存,力扣那道题的广搜技巧到在这道题里面用不了,n,m范围太大了,转为二进制最大就是15
15。但可以用深搜,因为如果要最小的操作达到目标状态,一个格子最多翻一次。而且我们一旦确定了矩阵边界(某一行或某一列的状态)整个矩阵的状态都被确定了,如下图
在这里插入图片描述
第一列已经确定,由于现在能够影响第一列的只有第二列所以要达到目标状态第二列状态只能是
第一行:不翻;第二行:翻;第三行:不翻‘第四行:翻
因此我们只需要二进制枚举边界的反转状况,得到所有的可能,然后取最小就行。

//#include<bits/stdc++.h>
#include<queue>
#include <cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (1000000007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
#define MP(x,y) make_pair(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int inf_max = 0x3f3f3f3f;
const ll Linf = 9e18;
const int maxn = 2e5 + 10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
#define MP(x,y) make_pair(x,y)
typedef pair<int,int> P;
int n,m,mat[20][20],mat_copy[20][20],ret[20][20];
int dx[5] = {0,0,0,1,-1};
int dy[5] = {0,1,-1,0,0};
vector<P>path,min_path;
void convert(int (&mat1)[20][20],int x,int y) {
    for(int i = 0; i < 5; ++i) {
        int tx = x + dx[i],ty = y + dy[i];
        if(tx >= 1 && tx <= n && ty >= 1 && ty <= m) mat1[tx][ty] ^= 1;
    }
}
int main()
{
    n = read();m = read();
    for(int i = 1;i <= n; ++i) {
        for(int j = 1;j <= m; ++j) {
            mat[i][j] = read();
        }
    }
    int cur = 0,ans = inf_max;
    for(int i = 0;i < (1 << m); ++i) {
        cur = 0;path.clear();
        for(int j = 1;j <= n; ++j) {
            for(int k = 1;k <= m; ++k){
                mat_copy[j][k] = mat[j][k];
            }
        }
        for(int j = 0;j < m; ++j) {
            if(i & (1 << j)) {
                cur++;convert(mat_copy,1,j + 1);path.push_back(MP(1,j + 1));
            }
        }
        for(int j = 2;j <= n; ++j) {
            for(int k = 1;k <= m; ++k) {
                if(mat_copy[j - 1][k]) {
                    cur++;convert(mat_copy,j,k);path.push_back(MP(j,k));
                }
            }
        }
        int flag = 0;
        for(int j = 1;j <= m;++j) {
            if(mat_copy[n][j]) {
                flag = 1; break;
            }
        }
        if(!flag) {
            if(ans == inf_max) {
                ans = cur;min_path = path;
            }else if(ans > cur){
                ans = cur;min_path = path;
            }
        }
    }
    if(ans == inf_max) {
        puts("IMPOSSIBLE");return 0;
    }
    for(int i = 0;i < min_path.size(); ++i){
        P tmp = min_path[i];
        ret[tmp.first][tmp.second] = 1;
    }
    for(int i = 1;i <= n; ++i) {
        for(int j = 1;j <= m; ++j) {
            printf("%d%c",ret[i][j],j == m ? '\n' : ' ');
        }
    }
    return 0;
}
发布了35 篇原创文章 · 获赞 18 · 访问量 4146

猜你喜欢

转载自blog.csdn.net/qq_44077455/article/details/104079488