c++迷宮問題回溯法遞迴演算法

墨蓮玦發表於2018-10-21

c++迷宮問題回溯法遞迴演算法

本題採用棧和遞迴方法求解。(回溯法的概念請自行百度,簡而言之就是正常人走迷宮的思路,先走,遇到死路退回去)
迷宮被表示成為一個mxn的二維陣列,為了避免查詢邊界條件,我們用1包圍迷宮。這個陣列因此需要用maze[m+2][p+2]來宣告。老鼠在迷宮中任何時候的位置都能通過[i][j]表示。老鼠每次可以向八個方向移動,將其可能的方向預先定義在struct move中。

q move[q].a move[q].b
N -1 0
NE -1 1
E 0 1
SE 1 1
S 1 0
SW 1 -1
W 0 -1
NW -1 -1

當前位置[i][j]的下一個座標[g][h]表示為:
g=i+move[SW].a; h=j+move[SW].b
使用另一個陣列mark[m+2][p+2]記錄老鼠已經走過的地方。
棧Stack定義為Items型別的棧,Items型別定義為:

struct Items{
	int x,y,dir;
	};

完整的程式如下

#include<iostream>
#include<stdlib.h>
using namespace std;
#define m 20
#define p 20
int maze[m + 2][p + 2];
int mark[m + 2][p + 2];
void setMaze() {//設定迷宮形狀並輸出
	fill(maze[0], maze[0] + (m + 2)*(p + 2), 1);
	fill(mark[0], mark[0] + (m + 2)*(p + 2), 0);
	maze[0][0] = 0;
	int i, j;
	for (j = 1; j < 13; j++)maze[1][j] = 0;
	for (i = 1; i < 10; i++)maze[i][13] = 0;
	for (j = 7; j < p + 2; j++)maze[10][j] = 0;
	for (j = 0; j < p + 2; j++) {
		for (i = 0; i < m + 2; i++)cout << maze[i][j] << " ";
		cout << endl;
	}
}

struct offsets {//座標
	int a, b;
};
enum directions { N, NE, E, SE, S, SW, W, NW };
struct Items {//棧的型別
	int x, y, dir;
	Items(int a = 0, int b = 0, int c = 0) {
		x = a; y = b; dir = c;
	}
	void Print() {
		cout << "(" << x << "," << y << ")" << ends;
	}
};
template<class T>
class Stack
{
private:
	int top, capacity;
public:
	T*stack;//儲存棧元素的陣列
	Stack(int stackCapacity = m*p);
	bool IsEmpty();
	T& Top();//返回棧頂元素
	void Push(const T& item);//入棧
	void Pop();//刪除棧頂元素
	void Delete();
};
template<class T>
Stack<T>::Stack(int stackCpacity)//建構函式
{
	capacity = stackCpacity;
	if (capacity < 1) throw"stack capackty must be > 0";
	stack = new T[capacity];
	top = -1;
}
template<class T>
inline bool Stack<T>::IsEmpty()
{
	return top == -1;
}
template<class T>
inline T& Stack<T>::Top()
{
	if (IsEmpty())throw"Stack is empty";
	return stack[top];
}
template<class T>
void Stack<T>::Push(const T&x)
{
	stack[++top] = x;
}
template<class T>
void Stack<T>::Pop()
{
	if (IsEmpty())throw"Stack is empty. Cannot delete.";
	stack[top--] = 0;
}
template<class T>
void Stack<T>::Delete() {
	if (stack)
		delete[]stack;
}
Items t(1, 1, N);//初始位置和方向
Stack<Items> stack;
void path(Items temp) {
	static offsets move[8] = { -1,0,-1,1,0,1,1,1,1,0,1,-1,0,-1,-1,-1 };
	int i = temp.x; int j = temp.y; int d = temp.dir;
	if (d > NW) {//當前是死路
		stack.Pop();
		if (!stack.IsEmpty()) {
			temp = stack.Top();
			temp.dir++;
			path(temp);
		}
		else cout << "not find";
	}
	int g = i + move[d].a; int h = j + move[d].b;
	if ((g == m + 1) || (h == p + 1)) {//找到出口
		cout << "find" << endl;
		stack.Push(temp);
		while (!stack.IsEmpty()) {
			stack.Top().Print();
			stack.Pop();
		}
	}
	else if ((!maze[g][h]) && (!mark[g][h])) {//當前不是出口,依然能繼續走
		stack.Push(temp);//路徑放入棧
		mark[g][h] = 1;
		temp.x = g; temp.y = h; temp.dir = N;
		path(temp);//遞迴下一格
	}
	else//需要換方向
	{
		temp.dir++;
		path(temp);//遞迴下一格
	}
}
int main() {
	setMaze();
	path(t);
}

(第一次用,不會換顏色==)
程式結果:

0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
find
(10,20) (10,19) (10,18) (10,17) (10,16) (10,15) (10,14) 
(9,13) (8,13) (7,13) (6,13) (5,13) (4,13) (3,13) (2,13) 
(1,13) (1,12) (1,11) (1,10) (1,9) (1,8) (1,7) (1,6) (1,5) 
(1,4) (1,3) (1,2) (1,1) 

(雖然這個迷宮看起來非常沙雕,但是好在比較清晰)
ps:
1.棧未新增解構函式
2.迷宮沒有出路的情況還沒有測試,可能會出現bug
3.迷宮列印的結果是倒敘,請自行從後向前讀。
4.提醒一下老鼠移動的方向有8個,是可以斜著走的。
and哪位好心人能告訴我顏色怎麼調TAT

相關文章