【POJ1475】Pushing Boxes 推箱子

5 篇文章 0 订阅
4 篇文章 0 订阅

Pushing Boxes 推箱子


  • Description

推箱子是一款经典的小游戏,为简化问题,假设只有一个箱子。游戏在一个R行C列的由单位格子组成的区域中进行,每一步,你可以移动到相邻的四个格子中的一个,前提是那个格子是空的;或者,如果你在箱子旁边,你也可以推动箱子前进一格,当然不能推到区域外面。这里写图片描述
初始时你在其中某个格子内,你要把箱子推到指定格子。又由于箱子很重,所以你要用尽量少的推动次数。

  • Input Format

输入包含多组数据,每组数据第一行为两个正整数R和C,表示行数和列数。接下来R行,每行C个字符,描述游戏区域。用’#’表示石块,用’.’表示空的格子,你的起始位置为’S’,箱子起始位置为’B’,箱子目标位置为’T’。
输入以R=C=0结束。

  • Output Format

对于第i组数据,如果不能将箱子推到指定格子,那么输出一行”Impossible.”(不含引号);否则,输出具有最少推动次数的操作序列。如果有多个,则输出具有最少移动次数的操作序列。如果还有多个,输出任意一个即可。
操作序列是一行由’N’,’S’,’E’,’W’,’n’,’s’,’e’,w’组成的字符串,大写字母表示推动操作,小写字母表示移动操作,方向依次表示北,南,东,西。

  • Sample Input
1 7
SB....T
1 7
SB..#.T
7 11
###########
#T##......#
#.#.#..####
#....B....#
#.######..#
#.....S...#
###########
8 4
....
.##.
.#..
.#..
.#.B
.##S
....
###T
0 0
  • Sample Output

EEEEE
Impossible.
eennwwWWWWeeeeeesswwwwwwwnNN
swwwnnnnnneeesssSSS

  • Hint

【数据规模】
对于40%的数据,3<=R*C<=20;
对于100%的数据,1<=R,C<=20,且数据组数不超过3组;


  • 分析

我们都很清楚如果要推动箱子必须站在箱子旁边,所以我们把箱子位置和人的位置都记下来记为一个状态,然后跑Spfa。


#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Move_X[4]={0,0,1,-1},Move_Y[4]={1,-1,0,0};
struct Data{int x,y;}People,Box,Tag;
struct Info{
    Data P,B;
    int From,Push;
}Q[500000];
int Map[22][22],n,m,ans,Ans[50000],Dist[22][22][22][22],In[22][22][22][22];
inline bool operator == (Data a,Data b){return a.x==b.x && a.y==b.y;}
void write(int t){
    memset(Ans,0,sizeof(Ans));
    for (int i=t;i!=1;i=Q[i].From){
        int h=Q[i].From;
        if (Q[i].P.x==Q[h].P.x+1 && Q[i].P.y==Q[h].P.y){
            if (Q[i].B==Q[h].B) Ans[++Ans[0]]='s';
            else Ans[++Ans[0]]='S';
        }
        if (Q[i].P.x==Q[h].P.x-1 && Q[i].P.y==Q[h].P.y){
            if (Q[i].B==Q[h].B) Ans[++Ans[0]]='n';
            else Ans[++Ans[0]]='N';
        }
        if (Q[i].P.x==Q[h].P.x && Q[i].P.y==Q[h].P.y+1){
            if (Q[i].B==Q[h].B) Ans[++Ans[0]]='e';
            else Ans[++Ans[0]]='E';
        }
        if (Q[i].P.x==Q[h].P.x && Q[i].P.y==Q[h].P.y-1){
            if (Q[i].B==Q[h].B) Ans[++Ans[0]]='w';
            else Ans[++Ans[0]]='W';
        }
    }
    for (int i=Ans[0];i;i--) printf("%c",Ans[i]);
    printf("\n");
}
int main(){
    freopen("4.in","r",stdin);
    freopen("4.out","w",stdout);
    for (scanf("%d%d\n",&n,&m);n!=0;scanf("%d%d\n",&n,&m)){
        memset(Dist,127,sizeof(Dist));
        memset(In,0,sizeof(In));
        memset(Map,0,sizeof(Map));
        for (int i=1;i<=n;i++){
            for (int j=1;j<=m;j++){
                scanf("%c",&Map[i][j]);
                if (Map[i][j]=='S') People=(Data){i,j};
                if (Map[i][j]=='B') Box=(Data){i,j};
                if (Map[i][j]=='T') Tag=(Data){i,j};
                if (Map[i][j]=='#') Map[i][j]=1;
                else Map[i][j]=0;
            }
            scanf("\n");
        }
        for (int i=1;i<=n;i++) Map[i][0]=Map[i][m+1]=1;
        for (int i=1;i<=m;i++) Map[0][i]=Map[n+1][i]=1;
        Q[1]=(Info){People,Box,0,0};
        bool p=false;
        for (int h=1,t=1;h<=t;h++){
            In[Q[h].P.x][Q[h].P.y][Q[h].B.x][Q[h].B.y]=0;
            if (Q[h].P.x==1 && Q[h].P.y==2 && Q[h].B.x==5 && Q[h].B.y==4){
                int tag=0;
            }
            for (int i=0;i<4;i++){
                Data Move={Q[h].P.x+Move_X[i],Q[h].P.y+Move_Y[i]};
                if (Map[Move.x][Move.y]==0){
                    if (Move==Q[h].B){
                        if (Map[Q[h].B.x+Move_X[i]][Q[h].B.y+Move_Y[i]]==0){
                            if (Dist[Move.x][Move.y][Q[h].B.x+Move_X[i]][Q[h].B.y+Move_Y[i]]>Q[h].Push+1){
                                Dist[Move.x][Move.y][Q[h].B.x+Move_X[i]][Q[h].B.y+Move_Y[i]]=Q[h].Push+1;
                                if (In[Move.x][Move.y][Q[h].B.x+Move_X[i]][Q[h].B.y+Move_Y[i]]){
                                    int x=In[Move.x][Move.y][Q[h].B.x+Move_X[i]][Q[h].B.y+Move_Y[i]];
                                    Q[x].From=h;
                                    Q[x].Push=Q[h].Push+1;
                                }
                                else{
                                    In[Move.x][Move.y][Q[h].B.x+Move_X[i]][Q[h].B.y+Move_Y[i]]=++t;
                                    Q[t].P=Move;
                                    Q[t].B=(Data){Q[h].B.x+Move_X[i],Q[h].B.y+Move_Y[i]};
                                    Q[t].From=h;
                                    Q[t].Push=Q[h].Push+1;
                                }
                            }
                        }
                    }
                    else{
                        if (Dist[Move.x][Move.y][Q[h].B.x][Q[h].B.y]>Q[h].Push){
                            Dist[Move.x][Move.y][Q[h].B.x][Q[h].B.y]=Q[h].Push;
                            if (In[Move.x][Move.y][Q[h].B.x][Q[h].B.y]){
                                int x=In[Move.x][Move.y][Q[h].B.x][Q[h].B.y];
                                Q[x].From=h;
                                Q[x].Push=Q[h].Push;
                            }
                            else{
                                In[Move.x][Move.y][Q[h].B.x][Q[h].B.y]=++t;
                                Q[t].P=Move;
                                Q[t].B=Q[h].B;
                                Q[t].From=h;
                                Q[t].Push=Q[h].Push;
                            }
                        }
                    }
                }
                if (Q[t].B==Tag){
                    if (!p || Q[t].Push<Q[ans].Push) ans=t;
                    p=true;
                }
            }
        }
        if (p) write(ans);
        else printf("Impossible.\n");
    }
    fclose(stdin); fclose(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值