题意:
给你一个迷宫,求出从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;
} 
京公网安备 11010502036488号