俩种套路本质都是求最优解。
第一种是常见的从第一个点移动到另一个点,权值比较简单,例如走迷宫。
这种题一般每个点只会走一次,所以经常用bool vis来标记,没走过就走,走过就不管。
第二种就是稍微复杂一点,权值不在是简单的用bool来存储,而是用int类型的vis来标记,类似于dijkstra算法,例如洛谷上的P1126 机器人搬重物 。
附上代码分析一下
其中每一个push前都会有一个判断,就是判断权值是否是更优解的情况,这种题还比如P3956 [NOIP2017 普及组] 棋盘 。这种情况我的代码一般是懒更新,代码好读一些,可能访问点的数量会有增长,不过一般题目并不会很大,就用懒更新,而如果题目很大,每次比较完就应该更新,到后面代码的push很可能是指数级别的。可能会爆空间
写法基本差不多的。而第一种题一般都是P1443 马的遍历这样的。或者是简单的走迷宫那样的。
其实都是一种套路,只是条件将题目难度上升。
#include<bits/stdc++.h>
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
using ll = long long int;
const int N=55;
int mp[N][N];
int n,m;
int stx,sty,edx,edy;char stw;
int res=-1;
unordered_map<char,int>vis;
int st[N][N][5];//标记每个坐标的每个方向的最小step
struct node{
int x,y,step;
int w;
};
int mm[][2]={{0,0},{0,1},{1,0},{1,1}};
//判断新位置是否越界或者有障碍
bool check(node *temp){
//东 EE0,南 SS1,西 WW2,北 NN3
if(temp->w==0){
temp->y++;
for(int i=0;i<=3;i++){
int nx,ny;
nx=temp->x+mm[i][0];
ny=temp->y+mm[i][1];
if(nx<1||ny<1||nx>n||ny>m||mp[nx][ny]==1)return false;
}
return true;
}
else if(temp->w==1){
temp->x++;
for(int i=0;i<=3;i++){
int nx,ny;
nx=temp->x+mm[i][0];
ny=temp->y+mm[i][1];
if(nx<1||ny<1||nx>n||ny>m||mp[nx][ny]==1)return false;
}
return true;
}
else if(temp->w==2){
temp->y--;
for(int i=0;i<=3;i++){
int nx,ny;
nx=temp->x+mm[i][0];
ny=temp->y+mm[i][1];
if(nx<1||ny<1||nx>n||ny>m||mp[nx][ny]==1)return false;
}
return true;
}
else{
temp->x--;
for(int i=0;i<=3;i++){
int nx,ny;
nx=temp->x+mm[i][0];
ny=temp->y+mm[i][1];
if(nx<1||ny<1||nx>n||ny>m||mp[nx][ny]==1)return false;
}
return true;
}
}
void bfs(){
queue<node>q;
q.push({stx,sty,0,vis[stw]});
//东 EE,南 SS,西 WW,北 NN
//st[stx][sty][vis[stw]]=0;
while(!q.empty()){
node t=q.front();
q.pop();
//cout<<st[t.x][t.y][t.w]<<" "<<t.step<<endl;
//如果
if(st[t.x][t.y][t.w]<=t.step)continue;
st[t.x][t.y][t.w]=t.step;
if(t.x==edx&&t.y==edy){
if(res==-1)
res=t.step;
else
res=min(res,t.step);
}
//如果没有障碍,没有越界,push进去
//一旦有障碍或者越界,break
//如果答案没有增益,不push
node temp=t;
for(int i=1;i<=3;i++){
if(check(&temp)){//传指针进去,进行修改
//新的位置step+1大于之前记录的,则不push
if(st[temp.x][temp.y][temp.w]<=t.step+1)continue;
q.push({temp.x,temp.y,t.step+1,temp.w});
}
else break;
}
//计算俩个方向
int nw1=(t.w+1+4)%4;
int nw2=(t.w-1+4)%4;
//如果当前位置的该方向的step大于转+1的step
//添加
if(st[t.x][t.y][nw1]>t.step+1){
q.push({t.x,t.y,t.step+1,nw1});
}
if(st[t.x][t.y][nw2]>t.step+1){
q.push({t.x,t.y,t.step+1,nw2});
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mp[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<=4;k++){
st[i][j][k]=0x3f3f3f3f;
}
}
}
cin>>stx>>sty>>edx>>edy>>stw;
vis['E']=0;vis['S']=1;vis['W']=2;vis['N']=3;
bfs();
cout<<res<<endl;
return 0;
}