「POJ1475」Pushing Boxes 题解

本文网址:https://www.cnblogs.com/zsc985246/p/16621280.html ,转载请注明出处。

题目大意

一张 nm 列的地图,字符.表示空地,字符#表示墙,字符S表示人的起始位置,字符B表示箱子的起始位置,字符T表示箱子的目标位置。

求一种移动方案,使箱子移动的次数最少,在此基础上再让人移动的总步数最少。方案中使用大写的EWSN表示箱子的推动,使用小写的ewsn表示人的移动。n,m20

输入

两个整数 nm ,表示行数和列数。

接下来 n 行,每行 m 个字符,表示迷宫。

输入以0 0结束。

输出

首先输出迷宫的编号。

如果无法完成任务,输出Impossible.,否则,输出一个最小化推送次数的序列。

在每个测试用例后输出一个空白行。

思路

看到数据范围,首先考虑搜索。

为了提高效率,考虑 A*。

分析题目,使箱子移动的次数最少,在此基础上再让人移动的总步数最少,所以我们用迭代加深的思想。

Q:如何解决?

A:既然要推箱子,那 BFS 箱子就可以了。

Q:人推不到怎么办?

A:再来一个 BFS。这个 BFS 枚举人能到达的点,如果可以到达推箱子的点,就返回 true,否则返回 false。

Q:那最后如何输出?

A:在第二个 BFS 里记录到达推箱子的点的路径,最后拼接到一起。

代码实现

#include<bits/stdc++.h>
#define ll int
using namespace std;


ll n,m;//地图大小 
ll sx,sy,bx,by,tx,ty;//三个特殊位置 
ll maze[21][21];//地图 
string S;//寄存答案 
ll nt[4][2]={-1,0,1,0,0,1,0,-1};//方向 
char ntc[4]={'n' ,'s','e','w' };//对应的字母 

bool push_bfs(ll SX,ll SY,ll X,ll Y,ll ex,ll ey){//你能否到达推箱子的位置 
    //SX,SY为你的坐标,X,Y为箱子的坐标,ex,ey为推箱子的位置 

    queue<ll>qx,qy;//qx为x坐标,qy为y坐标 
    queue<string>qs;//答案字符串 
    ll vis[21][21]={};//标记 
    qx.push(SX),qy.push(SY),qs.push("");//初始状态 
    vis[SX][SY]=1;//打标记 
    while(!qx.empty()){
        ll x=qx.front(),y=qy.front();//当前坐标 
        string s=qs.front();//当前行走状态 
        qx.pop(),qy.pop(),qs.pop();//出队 
        if(x==ex&&y==ey){//到达目标点 
            sx=x,sy=y,S=s;//记录你现在的位置及行走状态 
            return true;
        }
        for(ll i=0;i<4;i++){//四个方向 
            ll xx=x+nt[i][0],yy=y+nt[i][1];//下一个位置的坐标 
            if(xx<1||xx>n||yy<1||yy>m)continue;//出界 
            if(vis[xx][yy])continue;//被标记过 
            if(maze[xx][yy]==3)continue;//障碍 
            if(xx==X&&yy==Y)continue;//箱子 
            vis[xx][yy]=1;//打标记 
            qx.push(xx),qy.push(yy),qs.push(s+ntc[i]);//入队 
        }
    }
    return false;

} 

bool box_bfs(ll limit){

    queue<ll>qx,qy,qt,Qx,Qy;//qx为x坐标,qy为y坐标,Qx为你的x坐标,Qy为你的y坐标 
    queue<string>qs;//答案字符串 
    ll vis[21][21]={};//标记 
    qx.push(bx),qy.push(by),qt.push(0),Qx.push(sx),Qy.push(sy),qs.push("");//初始状态 
    vis[bx][by]=1;//打标记 
    while(!qx.empty()){
        ll x=qx.front(),y=qy.front(),t=qt.front(),X=Qx.front(),Y=Qy.front();//当前坐标 
        string s=qs.front();//当前行走状态 
        qx.pop(),qy.pop(),qs.pop(),Qx.pop(),Qy.pop();//出队 
        if(t>limit)continue;
        if(x==tx&&y==ty){
            cout<<s<<'\n';
            return true;
        }
        for(ll i=0;i<4;i++){//四个方向 
            ll xx=x+nt[i][0],yy=y+nt[i][1];//下一个位置的坐标 
            string ss=s;//下一个答案字符串 
            if(xx<1||xx>n||yy<1||yy>m)continue;//出界 
            if(vis[xx][yy])continue;//被标记过 
            if(maze[xx][yy]==3)continue;//障碍 
            if(!push_bfs(X,Y,x,y,x-nt[i][0],y-nt[i][1]))continue;//无法到达推箱子的位置 
            ss+=S;
            ss+=ntc[i]-32;
            sx=x,sy=y;
            vis[xx][yy]=1;//打标记 
            qx.push(xx),qy.push(yy),qt.push(t+1),Qx.push(sx),Qy.push(sy),qs.push(ss);//入队 
        }
    }
    return false;

}

int main(){

    ll cnt=0;
    while(cin>>n>>m){
        cnt++;
        if(n==0&&m==0)return 0;
        for(ll i=1;i<=n;i++){
            for(ll j=1;j<=m;j++){
                char c;
                cin>>c;
                if(c=='#')maze[i][j]=3;//障碍 
                if(c=='.')maze[i][j]=0;//路面 
                if(c=='S')maze[i][j]=1,sx=i,sy=j;//你的位置 
                if(c=='B')maze[i][j]=2,bx=i,by=j;//箱子 
                if(c=='T')maze[i][j]=0,tx=i,ty=j;//终点 
            }
        }
        cout<<"Maze #"<<cnt<<'\n';//格式 
        ll i;
        for(i=1;!box_bfs(i)&&i<=n*m;i++);//迭代加深 
        if(i==n*m+1)cout<<"Impossible.\n";//不可能 
        cout<<'\n';
    }

}

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

posted @   zsc985246  阅读(231)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示