【dfs+二进制枚举】—poj3279 fliptile

题目poj3279
分析此题:
二进制枚举:1 << m 种 情况——对第一行的翻牌情况进行枚举。
每张牌翻一次或不翻,(>=2相当于0,1);
dfs:对行dfs深搜,判断是否满足,满足则返回当前状况的翻牌次数。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>

#define MAXN 16

using namespace std;

int mapn[MAXN][MAXN], change[MAXN][MAXN], out[MAXN][MAXN];
int n, m;
int dir[5][2] = {{0, 0}, {0, 1}, {0, -1}, {1, 0}, {-1, 0}};

inline const int read(){
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9'){ if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){ x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
    return x * f;
}

int state(int x, int y){
    int sta = mapn[x][y];
    for(int i = 0; i < 5; i++){
        int x1 = x + dir[i][0];
        int y1 = y + dir[i][1];

        if(x1 < 1 || x1 > n || y1 < 1 || y1 > m) continue;
        sta += change[x1][y1];
    }

    return sta%2;  //%2 是显示现在黑或白
}

int dfs(){
    //核心语句
    for(int i = 2; i <= n; i++){    //从第二行开始遍历,直到最后一行完成
        for(int j = 1; j <= m; j++){  //二维矩阵——两个for循环
            if(state(i-1, j)){
                change[i][j] = 1;
            }
        }
    }

    //判断得结果,dfs()功能————当前枚举的第一行翻牌情况是否能实现,
    //若能返回当前的翻牌数
    for(int i = 1; i <= m; i++){   //判断最后一行之中:如果有黑子,返回no
        if(state(n, i)) return -1;
    }

    int cnt = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            cnt += change[i][j];  //有可能的情况,返回此时情况的翻牌数,便于遍历找到最小情况
    return cnt;
}


int main(){
    while(cin >> n >> m){
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                mapn[i][j] = read();

        int ans = 0x3f3f3f3f;
        bool flag = false;
        for(int i = 0; i < 1<<m; i++){
            memset(change, 0, sizeof(change));

            for(int j = 1; j <= m; j++){
                change[1][m-j+1] = i>>(j-1) & 1;    //枚举,将i代表的01串(一行所有的位置上各个牌翻不翻)逆序填入chang[1][]中
                //change[1][j] = i>>(j-1) & 1;   //也AC
            }
            int cont = dfs();
            if(cont < ans && cont >= 0){   //cont >= 0必须有,否则cont 返回为-1,被统计上
                flag = true;
                ans = cont;
               /* for(int i = 1; i <= n; i++){    //memcpy(out, change, sizeof(change));
                    for(int j = 1; j <= m; j++){
                        out[i][j] = change[i][j];
                    }
                }*/
                memcpy(out, change, sizeof(change));
            }
        }
        if(!flag) cout<<"IMPOSSIBLE"<<endl;
        else{
            for(int i = 1;i <= n;i ++){
                for(int j = 1;j <= m;j ++){
                    if(j != 1)  cout<<" ";
                    cout<<out[i][j];
                }
                cout<<endl;
            }
        }
    }
    return 0;
}

疑惑点:

  1. 第一行逆序,顺序都AC;

个人思路整理笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值