题意:
给你一个迷宫,求出从A到B最少需要多少次90度转弯。
思路:
这题和普通迷宫的区别在于:普通迷宫求的是最少走的步数,而这题要我们求的是最少的转弯数,这就导致了dfs的方式对于这题是优于bfs的,因为dfs的状态记录更加方便,而bfs还得专门开数组来记录方向和判重。
既然确定了解法,就可以开干了ヾ(•ω•`)o
首先是读入,没啥好说的,顺带记录一下A和B就行了。这里我采用了雨巨教的一个数记录两个坐标的方法,还是挺方便的,省得用pair。
for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { int pos = i*1000+j; scanf(" %c",&a[pos]); if(a[pos]=='A') A=pos; else if(a[pos]=='B') B=pos; } }
然后从A开始dfs,我这里使用了三个参数,分别记录(当前位置;当前方向;当前转弯数)。
当我们的操作格遇到B时,我们比较更新答案。当不是B时,我们记录一下在这个分支中,我们来过这个格子,以防出现来回访问的情况。
if(u==B) ans=min(dis,ans); if(met[u]) return; met[u]=true;
接下来就是走向下一个格子的操作了。
我们使用dx,dy数组操作的方式来确定下一个格子的坐标。
如果下一个格子的方向和现在的不一样,我们就在递归下一层的参数dis上加一。
if((i==0||i==2)&&dir!=0) { if(vis[pos_new]>=dis+1) { vis[pos_new]=dis+1; dfs(pos_new,0,dis+1); } } else if((i==1||i==3)&&dir!=1) { if(vis[pos_new]>=dis+1) { vis[pos_new]=dis+1; dfs(pos_new,1,dis+1); } }
如果方向相同,就不加。
else { if(vis[pos_new]>=dis) { vis[pos_new]=dis; dfs(pos_new,dir,dis); } }
这里要注意,因为它一开始的方向是任意的,于是我们就把它的方向设置成与横竖都不一样的,导致他开头第一步必转向,然后,再在输出结果的时候减去1就行了。
完整代码:
#include<iostream> #include<cstring> using namespace std; const int N = 1000010; char a[N]; int ans,A,B,n; int dx[]={0,1,0,-1},dy[]={1,0,-1,0}; int vis[N]; bool met[N]; void dfs(int u,int dir,int dis) { if(u==B) ans=min(dis,ans); if(met[u]) return; met[u]=true; for(int i=0;i<4;i++) { int x=u/1000+dx[i]; int y=u%1000+dy[i]; int pos_new=x*1000+y; if(x<0||x>=n||y<0||y>=n) continue; if(a[pos_new]=='x') continue; if((i==0||i==2)&&dir!=0) { if(vis[pos_new]>=dis+1) { vis[pos_new]=dis+1; dfs(pos_new,0,dis+1); } } else if((i==1||i==3)&&dir!=1) { if(vis[pos_new]>=dis+1) { vis[pos_new]=dis+1; dfs(pos_new,1,dis+1); } } else { if(vis[pos_new]>=dis) { vis[pos_new]=dis; dfs(pos_new,dir,dis); } } } met[u]=false; return; } int main() { ans=N; memset(vis,0x3f,sizeof vis); scanf("%d",&n); for(int i=0;i<n;i++) for(int j=0;j<n;j++) { int pos = i*1000+j; scanf(" %c",&a[pos]); if(a[pos]=='A') A=pos; else if(a[pos]=='B') B=pos; } vis[A]=0; dfs(A,3,0); if(ans!=N) cout<<ans-1; else cout<<-1; return 0; }