1. 程式人生 > >hdu 1254 推箱子 雙層bfs

hdu 1254 推箱子 雙層bfs

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL __int64
const int INF=1e8;
const int maxn=10;
int dir[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
int n,m;
struct node{
    int x,y;
};
struct node2{
    int x,y,xx,yy,step;//x,y是人所在位置,xx,yy為箱子所在位置
};
int e[maxn][maxn],vis[maxn][maxn],x3,y3,mark[maxn][maxn][5];

int bfs(int x1,int y1,int x2,int y2,int x,int y)//判斷人能否到達箱子前進方向的後方,即能否推箱子
{
    queue<node>qq;
    node ff,gg;
    int i,j,k,xx,yy;
    memset(vis,0,sizeof(vis));
    ff.x=x1;ff.y=y1;
    vis[x1][y1]=1;
    qq.push(ff);
    while(!qq.empty())
    {
        ff=qq.front();
        qq.pop();
        if(ff.x==x2&&ff.y==y2)
        {
            while(!qq.empty())
            qq.pop();
            return 1;
        }
        for(i=0;i<4;i++)
        {
            xx=ff.x+dir[i][0];
            yy=ff.y+dir[i][1];
            if(xx==x&&yy==y)continue;//箱子也是不能穿過的
            if(xx<0||yy<0||xx>=n||yy>=m||e[xx][yy]==1||vis[xx][yy]==1)continue;
            gg.x=xx;gg.y=yy;
            vis[xx][yy]=1;
            qq.push(gg);
        }
    }
    return 0;
}

void bfs2(int x1,int y1,int x2,int y2)//推箱子
{
    queue<node2>q;
    node2 f,g;
    int i,j,xx,yy,xxx,yyy;
    f.x=x1;f.y=y1;f.xx=x2;f.yy=y2;f.step=0;
    q.push(f);
    while(!q.empty())
    {
        f=q.front();
        q.pop();
        if(f.xx==x3&&f.yy==y3){printf("%d\n",f.step);while(!q.empty())q.pop();return;}
        for(i=0;i<4;i++)
        {
            xx=f.xx+dir[i][0];
            yy=f.yy+dir[i][1];
            xxx=f.xx-dir[i][0];
            yyy=f.yy-dir[i][1];
            if(xx<0||yy<0||xx>=n||yy>=m||xxx<0||yyy<0||xxx>=n||yyy>=m)continue;
            if(e[xx][yy]==1||e[xxx][yyy]==1||mark[xx][yy][i])continue;
            if(!bfs(f.x,f.y,xxx,yyy,f.xx,f.yy))continue;
            g.x=f.xx;g.y=f.yy;
            g.xx=xx;g.yy=yy;g.step=f.step+1;
            mark[xx][yy][i]=1;
            q.push(g);
        }
    }
    printf("-1\n");
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,k,x1,y1,x2,y2;
        x3=y3=-1;
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
            for(j=0;j<m;j++)
            {
                scanf("%d",&e[i][j]);
                if(e[i][j]==3){x3=i;y3=j;}
                if(e[i][j]==4){x1=i;y1=j;}
                if(e[i][j]==2){x2=i;y2=j;}
            }
        memset(mark,0,sizeof(mark));
        bfs2(x1,y1,x2,y2);
    }
    return 0;
}
/*
    推箱子,每次箱子進一個都要更新人的位置,還要判斷人是否能到箱子前進方向的後方,不然不能推。兩個bfs解決。
    這裡的難點就是箱子可能往回走,詳細見特例。所以直接標記位置是不可以的,還要標記推過了的方向,所以要三維陣列標記。(我在這背坑個半死。。)
特例:
4 3
0 0 0
0 0 1
0 2 3
1 4 1
6 3
0 0 0
0 0 0
1 0 0
0 0 1
0 2 3
1 4 1
*/