[蓝桥杯2015决赛]穿越雷区
题目描述
X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。
某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?
已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号或负号分别表示正负能量辐射区。
例如:
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -
坦克车只能水平或垂直方向上移动到相邻的区。
输入格式
输入第一行是一个整数n,表示方阵的大小, 4<=n<100
接下来是n行,每行有n个数据,可能是A,B,+,-中的某一个,中间用空格分开。
输入保证A,B都只出现一次。
输出格式
要求输出一个整数,表示坦克从A区到B区的最少移动步数。
如果没有方案,则输出-1
输入样例
5
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -
输出样例
10
代码展示:
#include<bits/stdc++.h>
using namespace std;
const int MAX=105;
char g[MAX][MAX];//用于存储地图
int res[MAX][MAX];//用于存储结果
bool vis[MAX][MAX];//用于标记是否走过
int n,x2,y2;//n为地图的大小,x2、y2分别为'B'的横纵坐标
int v1[4]={-1,0,1,0},v2[4]={0,-1,0,1};//用于进行上下左右操作
typedef pair<int,int>PII;//用于存储点的信息
void bfs(int x,int y){
queue<PII>q;
//由于传入的x,y是'A'的坐标,而不是'+'或'-'的坐标
//故先将其周围的满足条件的'+'或'-'压入队列,并将其标记
for(int i=0;i<4;i++){
if((x+v1[i]>=0)&&(x+v1[i]<n)&&(y+v2[i]>=0)&&(y+v2[i]<n)){
q.push({x+v1[i],y+v2[i]});
res[x+v1[i]][y+v2[i]]+=1;
}
}
//只要队列非空,则弹出队首,将其标记
while(!q.empty()){
PII start=q.front();
q.pop();
vis[start.first][start.second]=true;
//对上下左右进行判断
for(int i=0;i<4;i++){
int f=start.first+v1[i];
int s=start.second+v2[i];
//如果满足以下条件,则将其周围的点坐标压入队列,并进行相应的标记,结果数组相对应位置的路径长度加1
if((g[start.first][start.second]=='+')&&(g[f][s]=='-')&&vis[f][s]==false)
{
vis[f][s]=true;
res[f][s]=res[start.first][start.second]+1;
q.push({f,s});
}
else if((g[start.first][start.second]=='-')&&(g[f][s]=='+')&&vis[f][s]==false){
vis[f][s]=true;
res[f][s]=res[start.first][start.second]+1;
q.push({f,s});
}
//如果已经到达了'B',即终点 ,则结果数组相对应位置的路径长度加1,直接结束函数。
else if(g[f][s]=='B'){
res[f][s]=res[start.first][start.second]+1;
return;
}
}
}
}
int main(){
cin>>n;
int x1,y1;
//对地图进行初始化并记录下'A'和'B'的相应坐标
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>g[i][j];
if(g[i][j]=='A'){
x1=i,y1=j;
}
if(g[i][j]=='B'){
x2=i,y2=j;
}
}
}
bfs(x1,y1);
//输出坦克从A区到B区的最少移动步数
cout<<res[x2][y2]<<endl;
return 0;
}