题目:定义一个二维数组 N*M ,如 5 × 5 数组下所示:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。
从入口开始,检测当前位置的四个方向是否存在可行的位置P,将P放入队列中,将当前位置存储的距离加1后,替换位置P的值。接着从队列中取出下一位置。重复同样的操作,直到下一个位置是出口即可停止。
寻找最短路径则比较简单,经过的位置都存储了距离入口的距离,从出口的距离逆向寻找距离递减的路径就是最短路径。最短路径可能不止一条。
0 1 0 0 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
---------------------------------------------------------------------------------------------------------------------------------
2 1 0 11 10
3 1 1 1 9
4 5 6 7 8 ---------------------> 10 9 8 7 6 5 4 3 2
5 1 1 1 9 |
6 7 8 1 10 |
V
2 3 4 5 6 7 8 9 10
(0,0),(1,0),(2,0),(2,1),(2,2),(2,3),(2,4),(3,4),(4,4)
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct Pos {
int x;
int y;
};
bool findRoad(vector<vector<int>>&map, vector<Pos>&road) {
if (map.size() < 1)return false;
int endx = map.size() - 1;
int endy = map[0].size() - 1;
queue<Pos> que;
que.push({ 0,0 });
map[0][0] = 2;
while (!que.empty()) {
Pos front = que.front();
que.pop();
int cx = front.x;
int cy = front.y;
if (cx == endx && cy == endy) {//当前位置位于出口,此时已经找到路径
cx = endx;
cy = endy;
road.push_back({ cx,cy });
while (!(cx == 0 && cy == 0)) {
if (cx - 1 >= 0 && map[cx - 1][cy] == map[cx][cy] - 1) { --cx; road.push_back({ cx,cy }); }
else if (cx + 1 < map.size() && map[cx + 1][cy] == map[cx][cy] - 1) { ++cx; road.push_back({ cx,cy }); }
else if (cy - 1 >= 0 && map[cx][cy - 1] == map[cx][cy] - 1) { --cy; road.push_back({ cx,cy }); }
else if (cy + 1 < map[0].size() && map[cx][cy + 1] == map[cx][cy] - 1) { ++cy; road.push_back({ cx,cy }); };
}
return true;
}
int d = map[cx][cy];
if (cx - 1 >= 0 && map[cx - 1][cy] == 0) { que.push({ cx - 1,cy }); map[cx - 1][cy] = d + 1; }
if (cx + 1 < map.size() && map[cx + 1][cy] == 0) { que.push({ cx + 1,cy }); map[cx + 1][cy] = d + 1; }
if (cy - 1 >= 0 && map[cx][cy - 1] == 0) { que.push({ cx,cy - 1 }); map[cx][cy - 1] = d + 1; }
if (cy + 1 < map[0].size() && map[cx][cy + 1] == 0) { que.push({ cx,cy + 1 }); map[cx][cy + 1] = d + 1; };
}
return false;
}
int main() {
int row, col;
cin >> row >> col;
int pos;
vector<vector<int>> map(row, vector<int>(col));
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
cin >> pos;
map[i][j] = pos;
}
}
vector<Pos> road;
findRoad(map, road);
for (auto it = road.rbegin(); it != road.rend(); ++it) cout << "(" << it->x << "," << it->y << ")" << endl;
}
上述是广度优先的寻路算法,每走一步都要回头看一下所过之地的其他路口;而深度优先则只要还能继续走就绝不回头。下图是广度优先和深度优先不同的搜索过程。算法的核心思想几乎一致,只是区别于所有的数据结构式栈还是队列,所取得下一个节点也就分为最早放入的和刚放入的。
下面是基于Easyx写的一个演示代码,包括迷宫的生成和寻路。为了提高出图速度,一些地方耦合度较大,看起来可能会比较跳跃。
#include <iostream>
#include<graphics.h>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
struct Position {
int i;
int j;
int state;
};
enum State { WALL = -1, ROAD = 0, DISABLE = -2 };
class Maze {
private:
int width = 3;
int height = 3;
int size = 10;
int color_depth = 0;
vector<vector<int>> map;
vector<Position> buffer;
vector<Position> road_buffer;
int buffer_size = 0;
vector<pair<int, int>> sliding_queue;
int sliding_queue_begin = 0;
int sliding_queue_end = 0;
public:
Maze(int _width, int _height, int _size);
~Maze() = default;
int getWidth();
int getHeight();
void init();
void create();
void draw();
void drawRoad();
void BFS(int sx, int sy, int ox, int oy);
void DFS(int sx, int sy, int ox, int oy);
};
Maze::Maze(int _width, int _height,int _size) :width(_width), height(_height),size(_size) {
width /= size;
height /= size;
if (width % 2 == 0) width -= 1;
if (height % 2 == 0) height -= 1;
map.resize(width, vector<int>(height));
buffer.resize(width * height);
sliding_queue.resize((width - 1) * (height - 1) / 4);
}
int Maze::getWidth()
{
return this->width;
}
int Maze::getHeight()
{
return this->height;
}
void Maze::init() {
buffer_size = 0;
for (int i = 0; i < map.size(); ++i) {
for (int j = 0; j < map[i].size(); ++j) {
if (i % 2 == 0 || j % 2 == 0) map[i][j] = WALL;
else map[i][j] = ROAD;
buffer[buffer_size] = { i,j, map[i][j] };
++buffer_size;
}
}
}
void Maze::draw() {
BeginBatchDraw();
for (int i = 0; i < buffer_size; ++i) {
if (buffer[i].state == WALL) {
setfillcolor(RGB(60,60,60));
}
else if (buffer[i].state == ROAD) {
setfillcolor(WHITE);
}
else {
int g = 255-int(255.0f* map[buffer[i].i][buffer[i].j] / color_depth);
setfillcolor(RGB(0,g,0));
}
solidrectangle(buffer[i].i * size, buffer[i].j * size, (buffer[i].i + 1) * size, (buffer[i].j + 1) * size);
}
FlushBatchDraw();
}
void Maze::drawRoad() {
BeginBatchDraw();
for (int i = 0; i < road_buffer.size(); ++i) {
if(i==0||i==road_buffer.size()-1) setfillcolor(BLUE);
else setfillcolor(RED);
solidrectangle(road_buffer[i].i * size, road_buffer[i].j * size, (road_buffer[i].i + 1) * size, (road_buffer[i].j + 1) * size);
}
FlushBatchDraw();
}
void Maze::create() {
buffer_size = 0;
sliding_queue_begin = 0;
sliding_queue_end = 1;
sliding_queue[0] = { 1,1 };
map[1][1] = DISABLE;
vector<pair<int, int>> next(4);
int num = 0;
while (sliding_queue_begin < sliding_queue_end) {
int s0 = sliding_queue_begin + rand() % (sliding_queue_end - sliding_queue_begin);
pair<int, int> cur = sliding_queue[s0];
if (sliding_queue_begin + 1 < sliding_queue_end) {
sliding_queue[s0] = sliding_queue[sliding_queue_begin + 1];
sliding_queue[sliding_queue_begin + 1] = cur;
}
++sliding_queue_begin;
while (true) {
if (cur.first > 2 && map[cur.first - 1][cur.second] == WALL && map[cur.first - 2][cur.second] == ROAD) {
next[num] = { -1,0 };
++num;
}
if (cur.second > 2 && map[cur.first][cur.second - 1] == WALL && map[cur.first][cur.second - 2] == ROAD) {
next[num] = { 0,-1 };
++num;
}
if (cur.first < map.size() - 3 && map[cur.first + 1][cur.second] == WALL && map[cur.first + 2][cur.second] == ROAD) {
next[num] = { 1,0 };
++num;
}
if (cur.second < map[0].size() - 3 && map[cur.first][cur.second + 1] == WALL && map[cur.first][cur.second + 2] == ROAD) {
next[num] = { 0,1 };
++num;
}
if (num < 1) break;
int s = rand() % num;
num = 0;
map[cur.first + next[s].first][cur.second+ next[s].second] = DISABLE;
map[cur.first + 2 * next[s].first][cur.second + 2 * next[s].second] = DISABLE;
cur = { cur.first + 2 * next[s].first,cur.second + 2 * next[s].second };
sliding_queue[sliding_queue_end] = { cur.first,cur.second };
++sliding_queue_end;
}
}
for (int i = 0; i < map.size(); ++i) {
for (int j = 0; j < map[i].size(); ++j) {
if (map[i][j] == DISABLE) {
buffer[buffer_size] = { i,j ,ROAD };
++buffer_size;
map[i][j] = ROAD;
}
}
}
}
void Maze::BFS(int sx, int sy, int ox, int oy) {
buffer_size = 0;
queue<Position> next;
next.push({ sx, sy,2});
while (!next.empty()) {
Position cur = next.front();
next.pop();
map[cur.i][cur.j] = cur.state;
buffer[buffer_size] = { cur.i,cur.j,DISABLE };
++buffer_size;
if (ox == cur.i && oy == cur.j) {
color_depth = map[ox][oy];
int cx = ox;
int cy = oy;
road_buffer.clear();
road_buffer.push_back({ cx,cy });
while (!(cx == sx && cy == sy)) {
if (cx > 1 && map[cx - 1][cy] == map[cx][cy] - 1) { --cx; road_buffer.push_back({ cx,cy }); }
else if (cx < map.size() - 2 && map[cx + 1][cy] == map[cx][cy] - 1) { ++cx; road_buffer.push_back({ cx,cy }); }
else if (cy > 1 && map[cx][cy - 1] == map[cx][cy] - 1) { --cy; road_buffer.push_back({ cx,cy }); }
else if (cy < map[0].size() - 2 && map[cx][cy + 1] == map[cx][cy] - 1) { ++cy; road_buffer.push_back({ cx,cy }); };
}
break;
}
if (cur.i > 1 && map[cur.i - 1][cur.j] == ROAD) {
next.push({ cur.i - 1,cur.j ,cur.state + 1 });
}
if (cur.j > 1 && map[cur.i][cur.j - 1] == ROAD) {
next.push({ cur.i,cur.j - 1 ,cur.state + 1 });
}
if (cur.i < map.size() - 2 && map[cur.i + 1][cur.j] == ROAD) {
next.push({ cur.i + 1,cur.j ,cur.state + 1 });
}
if (cur.j < map[0].size() - 2 && map[cur.i][cur.j + 1] == ROAD) {
next.push({ cur.i,cur.j + 1,cur.state + 1 });
}
}
}
void Maze::DFS(int sx, int sy, int ox, int oy) {
buffer_size = 0;
stack<Position> next;
next.push({ sx, sy ,2});
while (!next.empty()) {
Position cur = next.top();
next.pop();
map[cur.i][cur.j] = cur.state;
buffer[buffer_size] = { cur.i,cur.j,DISABLE };
++buffer_size;
if (ox == cur.i && oy == cur.j) {
color_depth = map[ox][oy];
int cx = ox;
int cy = oy;
road_buffer.clear();
road_buffer.push_back({ cx,cy });
while (!(cx == sx && cy == sy)) {
if (cx > 1 && map[cx - 1][cy] == map[cx][cy] - 1) { --cx; road_buffer.push_back({ cx,cy }); }
else if (cx < map.size() - 2 && map[cx + 1][cy] == map[cx][cy] - 1) { ++cx; road_buffer.push_back({ cx,cy }); }
else if (cy > 1 && map[cx][cy - 1] == map[cx][cy] - 1) { --cy; road_buffer.push_back({ cx,cy }); }
else if (cy < map[0].size() - 2 && map[cx][cy + 1] == map[cx][cy] - 1) { ++cy; road_buffer.push_back({ cx,cy }); };
}
break;
}
if (cur.i > 1 && map[cur.i - 1][cur.j] == ROAD) {
next.push({ cur.i - 1,cur.j ,cur.state + 1 });
}
if (cur.j > 1 && map[cur.i][cur.j - 1] == ROAD) {
next.push({ cur.i,cur.j - 1 ,cur.state + 1 });
}
if (cur.i < map.size() - 2 && map[cur.i + 1][cur.j] == ROAD) {
next.push({ cur.i + 1,cur.j ,cur.state + 1 });
}
if (cur.j < map[0].size() - 2 && map[cur.i][cur.j + 1] == ROAD) {
next.push({ cur.i,cur.j + 1,cur.state + 1 });
}
}
}
int main()
{
srand(unsigned int(time(0)));
HWND hwnd = initgraph(640, 480);
SetWindowText(hwnd, L"Maze");
Maze maze(getwidth(), getheight(), 2);
while (true) {
maze.init();
maze.draw();
maze.create();
maze.draw();
system("pause");
maze.BFS(159, 105, maze.getWidth() - 2, maze.getHeight() - 2);
maze.draw();
system("pause");
maze.drawRoad();
system("pause");
}
system("pause");
closegraph();
}