这一篇博客质量不咋地,思路有点复杂,建议去看使用优先队列的。
基本思路在注释中写了。
不行了,渣渣一个,只能写到肝疼,洗洗睡了。
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int MAXN = 200 + 5, INF = 99999999;
int dir[4][2] = { -1, 0, 1, 0, 0, -1, 0, 1 };
typedef struct point {
int x, y, t;//t记录到达(x, y)点的最短时间
}point;
char map[MAXN][MAXN];//地图
int n, m;//地图大小
int can(point p) {//判断一个点是否在地图上且不是墙
if (p.x >= 0 && p.y >= 0 && p.x < n && p.y < m && map[p.x][p.y] != '#') return 1;
return 0;
}
int main() {
int flag;
point S, c;
vector<point> vec;//这里用了vector存储标记数组
queue<point> Q;
queue<point> b;
/*借助b队列模拟实现优先队列功能
把Q中取出来的点进行扩展
只要是可以走的点且不为x,则时间+1;如果是x则时间需要再加1
这时把扩展为x的点存到b中,在被扩展的点完成之后,在把b中的点加到Q的末端
这样就实现了Q中元素时间从小到大排列
*/
vector<point>::iterator it;
while (cin >> n >> m) {
flag = 0;
Q = queue<point>();
b = queue<point>();
vec.clear();
for (int i = 0; i < n; i++)
cin >> map[i];
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (map[i][j] == 'a') {
S.x = i;
S.y = j;
S.t = 0;
}
vec.push_back(S);
Q.push(S);
while (!Q.empty()) {
int loc = 0;
point p0 = Q.front();
Q.pop();
for (int i = 0; i < 4; i++) {
point p;
p.x = p0.x + dir[i][0];
p.y = p0.y + dir[i][1];
p.t = p0.t + 1;//在上一个点的时间时间上+1,因为走了一步
if (!can(p)) continue;//该点非法或不可走时,直接到下一个检索的点
for (it = vec.begin(), loc = 0; it != vec.end(); it++, loc++) {
if ((*it).x == p.x && (*it).y == p.y) {
break;
}
if (it == vec.end() - 1) {
c = p;
c.t = INF;
vec.push_back(c);
loc++;
break;
}
}
switch (map[p.x][p.y]) {
case 'r':
flag = 1;
cout << p.t << endl;
break;
case '.':
if (vec[loc].t <= p0.t) break;
Q.push(p);
vec[loc].t = p0.t;
break;
case 'x':
if (vec[loc].t <= p.t + 1) break;
c = p;
c.t++;//因为x代表守卫,需要多一个时间,所以在上面的这个if判断也要有一个+1的操作
b.push(c);
vec[loc].t = p0.t + 1;
break;
}//switch
if (flag == 1)
break;
}//for
if (flag == 1)
break;
while (!b.empty()) {
Q.push(b.front());
b.pop();
}//if(!b.empty())
}//while(!Q.empty())
if (flag == 0)
cout << "Poor ANGEL has to stay in the prison all his life." << endl;
}//while(cin >> n >> m)
}