这题 Memory Limit Exceeded Memory Limit:32768 K本题在测试机上是35343K
这题如果想AC可以不用看本人的话了....因为超了内存,如果只是想了解思想,强烈推荐,感觉还是很不错滴~自卖自夸下
这题我用了visit 来记录了所有能到达结点的最短路径数(并不需要全做,只要到了目的地就可以retun结束)【想了一下这句话也是错了,原因很简单,虽然正常来说在队列中先被访问的一定是比较近的点,但是由于此题有n怪物,所以不一定是最近的,有可能目的地确实先被访问了,但它其实可以被松弛操作,意思它途径了n怪物点,因此它不是最近的路径,此时return了答案可能会不对】因此超了内存,开始思路有点乱,又想通过路径数来找找路径,又想用方向数组来指向
找路径,又想通过标记方向数组 -> 或者 <- 来找路径 后来用数字模拟方向
用dri 记录所有点到达map[0][0]的路径,逆推 1 ( -> )东 2 ( v )南 3 ( <- ) 西 4 ( ^ )北
重理思路:
之前说不需要做最短路径数是不对的,后来想了想,如果没有最短路径数那么就没办法确定是否做松弛操作,没法确定是否做松弛操作就没法确定是否修改指向.... 因此此题超内存.....当遇到目的地后直接return 剩下点都不用计算了,可能会....节省点内存
1: 首先思想BFS用队列实现
2 : 路径的最后输出又栈实现【可由数组代替】
从(0,0)开始入队,读取到一个当前节点 p 就遍历他的四周所有可行点,如果【第一次发现这个节点】,将这个节点入队,然后标记路径长,为当前 p 节点路径+1,如果是 n,
那么就再 +n (注 * 前面+1必做),如果遍历发现这个节点【不第一次发现这个节点】,那么就看能否松弛【松弛操作】,就是当前 p 节点+1是否小于这个节点目前的路径数,如果小于,那么这个节点还需要入队列,并且修改最短路径
如果不小于说明不用做 ---------以上BFS可以求出所有可到达节点的最短路径长度
(其实通过所有最短路径数也是可以逆推出路径的,从目的结点开始每次少1步就是,遇到n,减去(n+1)即可)
因为路径数为6的结点周围可能3个都是路径数为7的,但是7的周围肯定只有1个,因此可以逆推,但是不方便,
所以加上指向肯定会更加方便找
因此本题思路来源于 BFS 两个串的最长共同子序列 (在数组中可以标记最短路径长度也可以给出路径的方向)如果有疑问可以看 算法导论的 BFS 例题讲解
下面的所有操作其实是加在上述的求最短路径数步骤中的,读者自行体会
依旧从(0,0)开始入队遍历周围每一个可行结点,如果第一次发现,将那个结点 标记下方向
【例如 当前点 p为 0,0发现向东走 0,1可以走,那么0,1点就标记为3(西)说明(0,1)向西走可以回到当前结点-这样从目的结点可以通过指向一路走到起始位置】
如果不是第一次,还是看是否能松弛,如果能松弛就修改指向
直至整个地图遍历结束
//下面的函数用来输出BFS后地图的所有能到达点的最短路径
for (i = 0; i < N; i++) {
for (j = 0; j < M; ++j) {
if (visit[i][j] == IFMAX)
cout << "X ";
else
cout << visit[i][j]<<" ";
}
cout << endl;
}//松弛后所有的地图信息已经清晰
//下面的函数用来输出地图的方向 1东 2 南 3西 4北 从 map[N-1][M-1]看方向到map[0][0]
for (i = 0; i < N; i++) {
for (j = 0; j < M; ++j) {
if (i == 0 && j == 0)
cout << "S";
else {
if (dri[i][j] == 0)
cout << "X";
else
cout << dri[i][j];
}
}
cout << endl;
}
//下面是源代码
# include <iostream>
# include <queue>
# include <stack>
#define IFMAX 200
using namespace std;
int N, M;//行 列
struct Path {
int x;
int y;
int p;
}p;
int visit[102][102];//题意 最大100*100
int dri[102][102];
char map[102][102];
int d[4][2] = { { 0,1 },{ 1, 0 },{ 0, -1 },{ -1, 0 } };
int min(int a, int b) {
return a < b ? a : b;
}
void PUSH(int dir_, queue<Path>&q) {
if (map[p.x][p.y] == '.') {//正常步子
if (p.p + 1<visit[p.x][p.y]) {//发现能被松弛就入栈
visit[p.x][p.y] = ++p.p;
q.push(p);
dri[p.x][p.y] = dir_;
}
}
else {//为n
if (visit[p.x][p.y] == IFMAX) {
q.push(p);//第一次访问入队
dri[p.x][p.y] = dir_;
}
visit[p.x][p.y] = min((p.p + 1 + (map[p.x][p.y] - '0')), visit[p.x][p.y]);//松弛操作是不是第一次入队都要做
if ((p.p + 1 + (map[p.x][p.y] - '0')) < visit[p.x][p.y]) {//可以被松弛
q.push(p);//可以松弛入队
dri[p.x][p.y] = dir_;
}
}
}
void check(queue<Path>&q) {
//地图信息 X . n
for (int i = 1; i < 5; ++i) {//东 南 西 北
p.x += d[i-1][0];
p.y += d[i-1][1];
if ((p.x >= 0 && p.x < N) && (0 <= p.y&&p.y < M) && map[p.x][p.y] != 'X') {//东
PUSH((((i+1)%4)+1), q);
}
p = q.front();//回溯原来位置
}
}
void BFS(void) {
queue<Path> q;
p.x = p.y = p.p = 0;
q.push(p);
while (!q.empty()) {
p = q.front();
p.p = visit[p.x][p.y];
check(q);//检查四周,将可入队的入队
q.pop();//将遍历过的出队
}//遍历完所有地图
}
void TravelStack(stack<Path> &s) {
int n, num = 0;
Path pi;
p = s.top();
s.pop();
while (!s.empty()) {
pi = p;
if (map[pi.x][pi.y] != '.') {
n = map[pi.x][pi.y] - '0';
for (int i = 0; i < n; ++i) {
cout << ++num << "s:FIGHT AT(" << pi.x << ", " << pi.y << ")" << endl;
}
}
p = s.top();
s.pop();
cout << ++num << "s:(" << pi.x << ", " << pi.y << ")->(" << p.x << ", " << p.y << ")" << endl;
}
cout << "FINISH" << endl;
}
void TrevealPath(void) {
p.x = N - 1;
p.y = M - 1;//终点标记起点位置
p.p = visit[N - 1][M - 1];
if (p.p == IFMAX) {//暗示了路径是不通的,所以呼叫上帝
cout << "God please help our poor hero.\nFINISH" << endl;
return;
}
stack<Path> s;
s.push(p);//起始点入栈
while (p.x != 0 || p.y != 0) {//终止位置不为(0,0)就循环
for (int i = 1; i < 5; ++i) {
if (dri[p.x][p.y] == i) {
p.x += d[i - 1][0];
p.y += d[i - 1][1];
s.push(p);
break;
}
}
}
cout << "It takes " << visit[N - 1][M - 1] << " seconds to reach the target position, let me show you the way." << endl;
TravelStack(s);
}
int main(void) {
while (cin >> N >> M) {// N 行 M 列
int i, j;
for (i = 0; i < N; i++) {
for (j = 0; j < M; ++j) {
cin >> map[i][j];
visit[i][j] = IFMAX;
dri[i][j] = 0;
}
}//录入地图信息
visit[0][0] = 0;
BFS();//BFS map信息
TrevealPath();
}
system("pause");
return 0;
}