码迷,mamicode.com
首页 > 其他好文 > 详细

POJ1753 状态压缩(+BFS) + 棋盘问题

时间:2016-07-13 17:08:08      阅读:127      评论:0      收藏:0      [点我收藏+]

标签:

0

棋盘问题,改变一个子的颜色,这个子以及这个子周围的四个位置(左右上下)的子分别变色,求最少的改变次数。

此类题大部分应该可以用状态压缩+暴力搜索解决。纯粹找规律不太合理。

 

1)第一种方法,状态压缩后BFS暴力搜索。因为棋盘很小,只有16个格子,枚举所有的状态共有2^16=65536种。所以有可以用int数组存储65535个状态用以确认哪一个出现了哪一个没出现,然后暴力枚举+BFS的搜索方式。

2)第二种,或者不进行状态压缩,直接按顺序,确定改变次数为1、改变次数为2...改变次数为16,在每一个确定的改变次数下用DFS求解。(直接DFS是从1到16一条路走到头然后不断回溯,第一次得到的颜色统一的改变次数未必是最小次数,所以改用有些BFS思想的DFS,但因为没有像BFS那样存储状态,所以做了一些重复的工作,时间会比第一种方法慢。)

 

 

3)WA,还未调试出来:

因为意识到解题的关键是,每一位置的子改变一次和改变两次其实是一样的&&改变第a个子然后改变第b个子的效果等同于先改变第b个子然后改变第a个子即与顺序无关,所以我设想不用状态压缩,直接按顺序只改变当前子之后的子不断BFS枚举,自然而然就可以避免重复的搜索工作。具体是指,第一轮,依次改变棋盘上第一个、第二个、第十六个子,共十六种情况存入队列,然后第二轮,从队列中取出改变第一个子后的状态,依次尝试改变第一个子往后的子,改变之后存入队列...第x轮,从队列中取出队首即上一轮中改变第m个子后的状态,那么我们只需考虑接下来改变第m个子之后的子即可,而不用考虑改变第m个子之前的子,因为那种情况相当于先改变第m个子之前的子此时改变第m个子。

我觉得我的思想应该没问题,起到的效果是等同于状态压缩中记录状态的作用的...不过就是没AC,样例过,疑问!?

 

1

1)

AC代码:

#include <iostream>
#include <queue>
#include <string.h>

using namespace std;
//int mmap[5][5]={0};
int dir[5][2]={{-1,0},{1,0},{0,-1},{0,1},{0,0}};
int visted[65536]={0};
int state[16];
int ini_state;
int flag;
int step;

struct boards{
    int state;
    int step;
};
queue<struct boards> q;
void initialize(){//☆这里可以打表
    int temp;
    int x,y;
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            temp=0;
            for(int l=0;l<5;l++){
                x=i+dir[l][0];
                y=j+dir[l][1];
                if(x<1||x>4||y<1||y>4){
                    continue;
                }
                temp^=(1<<( (x-1)*4+y -1 ));
            }
            state[(i-1)*4+j-1]=temp;
        }
    }
}
void Bfs(){
    struct boards cur_board;
    cur_board.state=ini_state;
    cur_board.step=0;
    q.push(cur_board);
    visted[cur_board.state]=1;
    while(!q.empty()){
        cur_board=q.front();
        q.pop();
        if(cur_board.state==0||cur_board.state==65535){
            step=cur_board.step;
            flag=1;
            return ;
        }
        struct boards next_board;
        for(int i=0;i<16;i++){
            next_board.state=cur_board.state^state[i];//☆这里可以马上判断一步,如果颜色统一立即return
            if(!visted[next_board.state]){
                next_board.step=cur_board.step+1;
                q.push(next_board);
                visted[next_board.state]=1;
            }
        }
    }
    return ;
}
int main(){
    ///initial
    ini_state=0;
    flag=0;
    step=0;
    char check;
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            cin>>check;
            if(check=='b')
                ini_state+=(1<< ( (i-1)*4+j - 1) );
            //cin>>mmap[i][j];
        }
    }
    //cout<<ini_state<<endl;
    initialize();//16 states of while board when only the piece was placed on the board.
    //for(int i=0;i<=15;i++){ cout<<state[i]<<endl;}


    ///bfs
    Bfs();


    ///result
    if(flag)
        cout<<step<<endl;
    else{
        cout<<"Impossible"<<endl;
    }
}


2)

AC代码:

#include <iostream>
#include <string.h>

using namespace std;
int mmap[5][5];
int dir[5][2]={{0,-1},{-1,0},{0,1},{1,0},{0,0}};//左 上 右 下 中
//int dir[5][5]={{-1,0},{1,0},{0,-1},{0,1},{0,0}};
int sum;
int flag=0;
int Judge(){
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            if(mmap[i][j]!=mmap[1][1]){
                return 0;
            }
        }
    }
    return 1;
}

void flip(int x,int y){
    for(int i=0;i<=4;i++){
        int x_next=x+dir[i][0];
        int y_next=y+dir[i][1];
        if(1<=x_next&&x_next<=4&&1<=y_next&&y_next<=4){
            mmap[x_next][y_next]=!mmap[x_next][y_next];
        }
    }
}

void Dfs(int x,int y,int obj,int cur_step){

    if(cur_step==obj){
       flag=Judge();
       return;
    }

    if(flag||x==5){
        return ;
    }

    flip(x,y);
/*
    if(y<4){
        Dfs(x,y+1,obj,cur_step+1);
    }
    else{
        Dfs(x+1,1,obj,cur_step+1);
    }
*/

    if(y+1<=4&&x<=4)
        Dfs(x,y+1,obj,cur_step+1);
    else if(y==4){
        Dfs(x+1,1,obj,cur_step+1);//不能写else if(y==4&&x+1<=4)因为判断函数(当cur_step==obj在dfs函数的开头,所以每一次翻转棋子之后,都应该调用dfs让其判断一次,如果因为x、y分别是最后一行最后一列了,因为x+1>4&&y==4而没有能进dfs直接把棋子翻转回来,return回到上一层,是不公平的,相当于这一轮对于最后一行最后一列的棋子翻转后没有进行判断是否是统一颜色了!!)
    }



    flip(x,y);//一定注意!不用bfs,而是dfs,每次改变的东西当return回来之后一定要状态还原!
/*
    if(y<4){
        Dfs(x,y+1,obj,cur_step);
    }
    else{
        Dfs(x+1,1,obj,cur_step);
    }
*/

    if(y+1<=4&&x<=4)
        Dfs(x,y+1,obj,cur_step);
    else if(y==4){
        Dfs(x+1,1,obj,cur_step);
    }


    return ;
}

int main(){
    memset(mmap,0,sizeof(mmap));
    char check;
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            cin>>check;
            if(check=='b'){
                mmap[i][j]=1;//b 1,w 0
            }
        }
    }
    int step=0;//当前翻转棋子个数
    for(int l=0;l<=16;l++){//应该翻转的棋子个数
       Dfs(1,1,l,step);
        if(flag==1){
            cout<<l<<endl;
            break;
        }
        if(l==16){
            cout<<"Impossible";
        }
    }
    return 0;
}


3)

WA代码第一份:

#include <iostream>
#include <queue>

using namespace std;
int sum;
int temp=0;
struct boards{
    char chess[4][4];
    int sum;
    int x_past;
    int y_past;
};
int dir[4][4]={{0,-1},{-1,0},{0,1},{1,0}};//左上右下
 queue <struct boards> q;
int Judge(struct boards boards_judge){

    char now=boards_judge.chess[0][0];
    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++){
            if(boards_judge.chess[i][j]!=now){
                return 0;
            }
        }
    }
    return 1;
}

int Reserve(){
    struct boards boards_cur;
    struct boards boards_future;
    if(q.empty()) return -1;
    boards_cur =q.front();

    q.pop();
    for(int i=boards_cur.x_past;i<4;i++){
        for(int j=boards_cur.y_past;j<4;j++){
            int x=i,y=j;
            if(x<0||x>3||y<0||y>3) continue;
            if(x==boards_cur.x_past&&y==boards_cur.y_past) continue;

            boards_future=boards_cur; //可以直接赋值
            boards_future.sum=boards_cur.sum+1;
            boards_future.x_past=i;
            boards_future.y_past=j;
            //cout<<"note:"<<boards_cur.sum<<endl;

            if(boards_cur.chess[i][j]=='b'){
                boards_future.chess[i][j]='w';
            }
            else{
                boards_future.chess[i][j]='b';
            }
            for(int l=0;l<4;l++){
                x=i+dir[l][0];
                y=j+dir[l][1];
                if(x<0||x>3||y<0||y>3) continue;
                if(boards_cur.chess[x][y]=='b'){
                    boards_future.chess[x][y]='w';
                }
                else{
                    boards_future.chess[x][y]='b';
                }
            }

            if(Judge(boards_future)){
                sum=boards_future.sum;
                return 1;
            }
            q.push(boards_future);
            //boards_cur.sum--;//!假如没有boards_future,直接q.push(boards_cur),然后再对boards_cur操作,是否,放入队列的就不再受影响----是的!不受影响

        }
    }
    return 0;
}
int main()
{
    struct boards board;
    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++){
            cin>>board.chess[i][j];
        }
    }
    board.sum=0;
    sum=0;
    board.x_past=-1;
    board.y_past=-1;
    q.push(board);
    if(Judge(board)){
    }
    else{
        while(1){//0-Lost 1-Win
            //temp+=1;
            int state=Reserve();
            if(state==1){
                break;
            }
            if(state==-1){
                sum=-1;
                break;
            }
        }
    }
    if(sum!=-1)
        cout<<sum<<endl;
    else{
        cout<<"Impossible"<<endl;
    }
}

 


WA代码第二份

#include <iostream>
#include <string.h>

using namespace std;
int mmap[4][4];
int dir[5][2]={{0,-1},{-1,0},{0,1},{1,0},{0,0}};//左 上 右 下 中
int sum;
int flag=0;
int Judge(){

    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++){
            if(mmap[i][j]!=mmap[1][1]){
                return 0;
            }
        }
    }
    return 1;
}
void flip(int x,int y){
    for(int i=0;i<=4;i++){
        int x_next=x+dir[i][0];
        int y_next=y+dir[i][1];
        if(0<=x_next&&x_next<=3&&0<=y_next&&y_next<=3){
            mmap[x_next][y_next]=!mmap[x_next][y_next];
        }
    }
}
void Dfs(int x,int y,int obj,int cur_step){
     if(flag)
        return ;
    if(cur_step==obj){
        if(Judge()){
            flag=1;
            sum=cur_step;
        }
        else {
            return ;
        }
    }

    for(int i=x;i<4;i++){
        for(int j=y;j<4;j++){
            if(i==x&&j==y){
                continue;
            }
            if(i<0||i>3||j<0||j>3){
                continue;
            }
            flip(i,j);

            Dfs(i,j,obj,cur_step+1);

            flip(i,j);
        }
    }
    return ;
}
int main(){
    memset(mmap,0,sizeof(mmap));
    char check;
    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++){
            cin>>check;
            if(check=='b'){
                mmap[i][j]=1;//b 1,w 0
            }
        }
    }
    int step=0;//当前翻转棋子个数
    for(int l=0;l<=16;l++){//应该翻转的棋子个数
        Dfs(0,-1,l,step);
        if(flag==1){
            cout<<sum<<endl;
            break;
        }
        if(l==16){
            cout<<"Impossible";
        }
    }
    return 0;
}


 

 

 

POJ1753 状态压缩(+BFS) + 棋盘问题

标签:

原文地址:http://blog.csdn.net/a272846945/article/details/51892875

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!