1. 程式人生 > >天天寫演算法之push box

天天寫演算法之push box

這個題的痛點在於思路問題,而且如何標記已經走過的路線,這裡的標記是標記人與三個箱子之間的相對位置,並不是說,你走過了以後,就不能再走了,只要其中一個箱子的位置發生了變化,那麼就可以繼續走。

程式碼是模的。也拓寬一下自己的思路。BFS用的還不是得心應手

#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;
}