「POJ1475」Pushing Boxes 题解
本文网址:https://www.cnblogs.com/zsc985246/p/16621280.html ,转载请注明出处。
题目大意
一张 行 列的地图,字符.
表示空地,字符#
表示墙,字符S
表示人的起始位置,字符B
表示箱子的起始位置,字符T
表示箱子的目标位置。
求一种移动方案,使箱子移动的次数最少,在此基础上再让人移动的总步数最少。方案中使用大写的EWSN
表示箱子的推动,使用小写的ewsn
表示人的移动。。
输入
两个整数 和 ,表示行数和列数。
接下来 行,每行 个字符,表示迷宫。
输入以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';
}
}
尾声
如果你发现了问题,你可以直接回复这篇题解
如果你有更好的想法,也可以直接回复!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现