poj_1735_Flip Game

一道需要活跃思维的搜索题,当然,对于2^16 的复杂度也可以枚举来做.


题目大意: http://poj.grids.cn/practice/1753/

给一个4*4的棋盘,上面有黑子 (用字符'b'表示) 和白子 (用字符'w'表示) .可以选择棋子翻转,每翻转一个棋子,其周围四个棋子也会被翻转(边角情况正常处理),问最少翻转多少次可以让棋盘全黑或全白.

解题思路:

一看只有16个格子,首先想到了枚举~:

for(int i=0;i<1;++i)

.

.

.

16层......后来一想这么写多丢人......所以还是搜索吧,bfs和dfs基本都没有问题,因为求最少步数,所以还是bfs比较适合.

把棋盘看做简单的0-1矩阵,对每一个位置取反时也会对周围4个位置取反,对一个数取反可以写做: n=n^1; .那么从什么状态开始搜素呢?~

将0-1矩阵合并,看成一个二进制数,那么他的范围仅仅为 0-0xffff 也就是一共仅有 0xfff 种状态.对每一位翻转,可以求出其状态转移方程:

   当前状态a ^ 转移状态i (i为翻转的位置),a==0 时结束,每个位置会有其单独的翻转状态.比如 0,0 位:

    1100  
    1000  
    0000  
    0000    周围四个位置取反.  

接下来就是么每一位的转移状态i的处理. 将矩阵每一位编号.

    F E D C  
    B A 9 8  
    7 6 5 4  
    3 2 1 0  

那么,其上下左右就为: 上: -4 下:+4 左:-1 右: +1 求转移状态的源码就为:


    void build() {  
        memset(no,0,sizeof(no));  
        int num=1;  
        for(int i=N;i>0;--i) {  
            for(int j=1;j<=4;++j) {  
                int tx=i*4-j;  
                no[num]=1<<(tx);  
                for(int k=0;k<4;++k) {  
                    int x=tx+dbit[k];  
                    if(x<0||x>15)  
                        continue;  
                    if((tx+4)%4==0&&(x+4)%4==3) {  
                        continue;  
                    }  
                    if((tx+4)%4==3&&(x+4)%4==0) {  
                        continue;  
                    }  
                    no[num]=no[num]+(1<<x);  
                }       
                num++;  
            }  
        }  
    }  

求出转移状态后,就以每一个点为起点bfs 即可:

    #include <myhead.h>  
    const int N=4;  
    const int s=0xffff;  
    const int t=0;  
    const int dbit[]={-4,1,+4,-1};  
    struct Node {  
        int m,num;  
        int i;  
    };  
    bool _hash[100000];  
    char a[N+1][N+1];  
    int no[20];  
    Node node;  
      
    void build() {  
        memset(no,0,sizeof(no));  
        int num=1;  
        for(int i=N;i>0;--i) {  
            for(int j=1;j<=4;++j) {  
                int tx=i*4-j;  
                no[num]=1<<(tx);  
                for(int k=0;k<4;++k) {  
                    int x=tx+dbit[k];  
                    if(x<0||x>15)  
                        continue;  
                    if((tx+4)%4==0&&(x+4)%4==3) {  
                        continue;  
                    }  
                    if((tx+4)%4==3&&(x+4)%4==0) {  
                        continue;  
                    }  
                    no[num]=no[num]+(1<<x);  
                }       
                num++;  
            }  
        }  
    }  
      
    bool init() {  
        for(int i=0;i<N;++i) {  
            if(scanf("%s",a[i])==EOF) {  
                return false;  
            }  
        }  
        memset(_hash,0,sizeof(_hash));  
        node.i=node.m=node.num=0;  
        int m=0;  
        for(int i=N-1;i>=0;--i) {  
            for(int j=N-1;j>=0;--j) {  
                if(a[i][j]=='b') {  
                    node.m=node.m+(1<<m);  
                }  
                m=m+1;  
            }  
        }  
        return true;  
    }  
      
    void bfs() {  
        queue<Node> q;  
        q.push(node);  
        while(!q.empty()) {  
            Node tmp=q.front();  
            q.pop();  
            if(tmp.m==s||tmp.m==0) {  
                printf("%d\n",tmp.num);  
                return ;  
            }  
            node.num=tmp.num+1;  
            for(int i=1;i<=16;++i) {  
                if(tmp.i!=i) {  
                    node.i=i;  
                    node.m=(tmp.m^no[i]);  
                    if(!_hash[node.m]) {  
                        _hash[node.m]=true;  
                        q.push(node);  
                    }  
                }  
            }  
        }  
        printf("Impossible");  
    }  
      
    int main()  
    {  
        build();  
        init();  
        bfs();  
        return 0;  
    }  


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值