题目: https://www.luogu.org/problemnew/show/P1126
题解:
#include<bits/stdc++.h>
using namespace std;
#define map mapp
bool map[51][51]; //存地图 ,检查是否越界
int vis[51][51]; //存访问过的最优解
struct yyy{int x,y,dir,st;}top;//定义队列中的元素
int ans[5001]={-1},minl=0x7fffff,ffx; //重要初始化
int fx[5][2]={{0,0},{0,1},{0,-1},{1,0},{-1,0}}; //方向打表
int main(){//输入+预处理地图
int n,m;
memset(map,0,sizeof(map));
memset(vis,0x3f3f3f3f3f,sizeof(vis));//memset赋极大值的技巧
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
bool a;
cin>>a;//将障碍块转化成点
if(a){map[i][j]=1;map[i-1][j-1]=1;map[i][j-1]=1;map[i-1][j]=1;}
}
for(int i=1;i<=n;i++){map[n][i]=1;map[i][m]=1;}//边界处理,注意分清n和m!!!!!!
int sx,sy,ex,ey;char sfx;
cin>>sx>>sy>>ex>>ey>>sfx;
//预处理搜索(主要是方向)
if(sfx=='E')ffx=1;
if(sfx=='W')ffx=2;
if(sfx=='S')ffx=3;
if(sfx=='N')ffx=4;//上北下南左西右东
//bfs
queue<yyy> Q;
Q.push((yyy){sx,sy,ffx,0});
while(!Q.empty()){
top=Q.front();Q.pop();
if(top.x==ex&&top.y==ey)minl=min(minl,top.st);//记录最小的步数
for(int i=1;i<=4;i++){//四向搜索
int step=top.st;
if(i!=top.dir){//转弯
step=top.st+1;//转一次
if((i==1&&top.dir==2)||(i==2&&top.dir==1)||(i==3&&top.dir==4)||(i==4&&top.dir==3))
step=top.st+2;//转两次
}
for(int j=1;j<=3;j++)//枚举步数
{
int xx,yy;
xx=top.x+j*fx[i][0];yy=top.y+j*fx[i][1];//注意分清m和n!!!!!!
if(xx>n||xx<1||yy>m||yy<1||map[xx][yy]) break;
//剪枝,同方向上有障碍或者越界就得换方向
if(vis[xx][yy]>step){
//上面这样写是错误的,比如向某方向走一步时,到达某个障碍,
//但是走三步就可能跳过障碍,机器人不能跳过障碍,与实际不符
Q.push((yyy){xx,yy,i,step+1});
vis[xx][yy]=step;
}
}
}
}
if(minl<0x7fffff) cout<<minl;
else cout<<-1;
return 0;
}
#include<iostream>
#include<cstring>
using namespace std;
bool map[51][51]; //存地图 ,检查是否越界
int vis[51][51]; //存访问过的最优解
struct yyy{int x,y,dir,st;}q[5001];//定义队列中的元素
int h=1,t;//队头、队尾
int ans[5001]={-1},tot,minl=0x7fffff; //重要初始化
int fx[5][2]={{0,0},{0,1},{0,-1},{1,0},{-1,0}}; //方向打表
int main(){//输入+预处理地图
int n,m;
memset(map,0,sizeof(map));
memset(vis,1,sizeof(vis));//memset赋极大值的技巧
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
bool a;
cin>>a;
if(a){//将块转化成点
map[i][j]=1;map[i-1][j-1]=1;map[i][j-1]=1;map[i-1][j]=1;
}
}
for(int i=1;i<=n;i++){map[n][i]=1;map[i][m]=1;}//边界处理,注意分清n和m!!!!!!
int sx,sy,ex,ey;
char sfx;
cin>>sx>>sy>>ex>>ey>>sfx;
//预处理搜索(主要是方向)
q[++t].x=sx,q[t].y=sy,q[t].st=0;
if(sfx=='E')q[t].dir=1;
if(sfx=='W')q[t].dir=2;
if(sfx=='S')q[t].dir=3;
if(sfx=='N')q[t].dir=4;//上北下南左西右东
//bfs
while(h<=t){
if(q[h].x==ex&&q[h].y==ey){ans[++tot]=q[h].st;}//可以优化
for(int i=1;i<=4;i++){//四向搜索
int step=q[h].st;
if(i!=q[h].dir){//转弯
step=q[h].st+1;//转一次
if((i==1&&q[h].dir==2)||(i==2&&q[h].dir==1)||(i==3&&q[h].dir==4)||(i==4&&q[h].dir==3))
step=q[h].st+2;//转两次
}
for(int j=1;j<=3;j++)//枚举步数
{
int xx,yy;
xx=q[h].x+j*fx[i][0];yy=q[h].y+j*fx[i][1];//注意分清m和n!!!!!!
if(xx>n||xx<1||yy>m||yy<1||map[xx][yy]) break;
//剪枝,同方向上有障碍或者越界就得换方向
if(vis[xx][yy]>step){
//if(xx<n&&xx>=1&&yy<m&&yy>=1&&map[xx][yy]==0&&vis[xx][yy]>step)
//上面这样写是错误的,比如向某方向走一步时,到达某个障碍,
//但是走三步就可能跳过障碍,机器人不能跳过障碍,与实际不符
q[++t].x=xx;q[t].y=yy;q[t].st=step+1;q[t].dir=i;
vis[xx][yy]=step;
}
}
}
h++;
}
for(int i=1;i<=tot;i++) if(ans[i]<minl) minl=ans[i];
if(minl<0x7fffff) cout<<minl;
else cout<<-1;
return 0;
}