HDU 1732——Push Box(BFS)

本文介绍了一种解决含有三个箱子的推箱子游戏问题的算法实现。通过使用8维哈希表来记录游戏状态,确保搜索过程中不会重复探索相同的状态。文章详细解释了如何判断下一步行动的合法性以及如何更新游戏状态。

3个箱子一个人,要想记录状态必须用8维的hash。

思路:

先判断下一步的位置是否合法

1、如果下一个点是   ' . '     ,判重,如果合法,则直接走到下个位置,记录状态,入队

2、如果下一个点是箱子,先判断是第几个箱子,然后判断同方向上的再下一个位置是不是箱子或者是墙,如果是墙或者箱子,说明当前箱子推不了,否则,就把当前序号的箱子推到那个位置上,改变它的坐标,判重,如果合法,则入队


弱菜的代码都是膜拜大牛的,只是加了个备注,自己按思路敲了一遍,ORZ

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
bool hash[8][8][8][8][8][8][8][8];
char map[8][8];
int n,m,ans;
int dir[4][2]={{0,1,},{0,-1},{1,0},{-1,0}};

struct node
{
    int x,y;
};

struct state
{
    node h,box[3];
    int st;
    bool isok()
    {
        if(h.x>=0&&h.x<n&&h.y>=0&&h.y<m&&map[h.x][h.y]!='#') return true;
        return false;
    }
}a,b;

void sethash(state cur)//记录状态
{

    hash[cur.h.x][cur.h.y][cur.box[0].x][cur.box[0].y][cur.box[1].x][cur.box[1].y][cur.box[2].x][cur.box[2].y]=true;
}

bool gethash(state cur)//判断当前状态是否走过
{
    return hash[cur.h.x][cur.h.y][cur.box[0].x][cur.box[0].y][cur.box[1].x][cur.box[1].y][cur.box[2].x][cur.box[2].y];
}
bool find(state cur)// 判断箱子是不是都推到洞里去了
{
    int i;
    for(i=0;i<3;++i){
        if(map[cur.box[i].x][cur.box[i].y]!='@') break;
    }
    if(i!=3) return false;
    return true;
}

int isbox(state cur)//判断这个位置是不是箱子,如果是,返回箱子的序号
{
    for(int i=0;i<3;++i){
        if(cur.h.x==cur.box[i].x&&cur.h.y==cur.box[i].y) return i;
    }
    return -1;
}

bool logic(state cur,int d,int cnt)//判断同方向上的下一个点,如果位置越界,或者是墙或箱子,返回false;
{
    state next;
    next.h.x=cur.h.x+dir[d][0];
    next.h.y=cur.h.y+dir[d][1];
    if(!next.isok()) return false;
    for(int i=0;i<3;++i){
        if(next.h.x==cur.box[i].x&&next.h.y==cur.box[i].y&&i!=cnt) return false;
    }
    return true;//可以推箱子
}
int bfs()
{
    queue<state> q;
    a.st=0;
    q.push(a);
    while(!q.empty()){
        a=q.front(),q.pop();
        if(find(a)){
            return ans=a.st;
        }
        for(int i=0;i<4;++i){
            b=a;
            b.h.x=a.h.x+dir[i][0];
            b.h.y=a.h.y+dir[i][1];
            b.st=a.st+1;
            if(!b.isok()) continue; //位置不合法

            int which=isbox(b); 
            if(which!=-1){//如果 这个位置是箱子
                if(logic(b,i,which)){ //同方向上的下个位置是路,把箱子推过去,改变它的坐标
                    b.box[which].x=b.h.x+dir[i][0];
                    b.box[which].y=b.h.y+dir[i][1];
                    if(!gethash(b)){//当前状态没有记录过
                        sethash(b);//记录状态
                        q.push(b);//入队
                    }
                }
            }
            else{//当前位置是路或者是洞,直接走
                if(!gethash(b)){
                    sethash(b);
                    q.push(b);
                }
            }
        }

    }
    return -1;


}
int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    while(scanf("%d%d",&n,&m)!=EOF){
        getchar();
        int cnt=0;
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                map[i][j]=getchar();
                if(map[i][j]=='X'){
                    a.h.x=i,a.h.y=j;
                }
                if(map[i][j]=='*'){
                    a.box[cnt].x=i,a.box[cnt++].y=j;//记录每个箱子的坐标
                }
            }
            getchar();
        }

        memset(hash,false,sizeof hash);
        sethash(a);
        printf("%d\n",bfs());
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值