Fliptile(枚举&DFS)

Fliptile

题目传送门

Fliptile

题目大意

给你一个 n × m n×m n×m的矩阵,矩阵由0和1组成,可以选择一个点翻转
翻转:将该点以及该点上下左右的点翻转(0变1,1变0)
求将矩阵翻转成全为0的最小步数,若没有则输出“IMPOSSIBLE”

思路

很经典的题目了,可以从第二行开始推,用第二行的翻转将第一行全变成0,同理,第三行变第二行为全0…
到最后一行时,判断该行是否为0,全为0即为这种方法可以。

对于第一行的状态可以直接枚举,枚举第一行翻转的情况(采取二进制的枚举方式),对于每次枚举的答案取最小即可

AC Code

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
#define endl '\n'
#define INF 0x3f3f3f3f
#define int long long
// #define TDS_ACM_LOCAL
const int N=20;
int ans;
int mp[N][N], s[N][N], tmp[N][N];
int dirx[]={0,1,0,-1,0};
int diry[]={0,0,1,0,-1};
int n, m;

bool check(int x, int y){   //求得(x,y)的颜色
    int temp=mp[x][y];
    for(int i=0; i<5; i++){
        int xx=x+dirx[i];
        int yy=y+diry[i];
        if(xx>=1 && xx<=n && yy>=1 && yy<=m)    temp+=tmp[xx][yy];
    }
    return temp&1;
}

int dfs(){
    for(int i=2; i<=n; i++)
        for(int j=1; j<=m; j++)
            if(check(i-1,j))    //上一行为黑色的地方翻转
                tmp[i][j]=1;

    for(int i=1; i<=m; i++)     //最后一行如果有黑色的就返回,该情况无效
        if(check(n,i))
            return INF;
    int temp=0;
    for(int i=1; i<=n; i++)     //计算当前枚举的情况的翻转次数
        for(int j=1; j<=m; j++)
            temp+=tmp[i][j];
    return temp;
}

void solve(){
    ans=INF;
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
            cin>>mp[i][j];
    
    for(int i=0; i<(1<<m); i++){    //枚举第一行的所有翻转的状态
        memset(tmp, 0,sizeof(tmp));
        for(int j=1; j<=m; j++)
            tmp[1][m-j+1]=(i>>(j-1)) &1;    //求得当前第一行的状态
        int cnt=dfs();
        if(cnt<ans){    //该解目前最优
            ans=cnt;
            memcpy(s, tmp, sizeof(tmp));    //将枚举的二维数组复制到答案中保存
        }
    }
    if(ans==INF)    {cout<<"IMPOSSIBLE"<<endl;   return ;}
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++)
            cout<<s[i][j]<<" ";
        cout<<endl;
    }
    return ;
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    solve();
    return 0;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值