1. 程式人生 > >【資料結構】棧實現迷宮尋路問題

【資料結構】棧實現迷宮尋路問題

思路:

解決迷宮求解的問題,從入口出發,順某一方向向前探索,若能走通,則繼續往前走;否則沿原路退回,換一個方向再繼續探索,直至所有可能的通路都探索到為止。為了保證在任何位置上都能沿原路退回,所以需要用一個後進先出的結構來儲存從入口到當前位置的路徑。因此,在求迷宮通路的演算法中要應用“棧”的思想假設“當前位置”指的是“在搜尋過程中的某一時刻所在圖中某個方塊位置”,則求迷宮中一條路徑的演算法的基本思想是:若當前位置“可通”,則放入“當前路徑”,並繼續朝“下一位置”探索,即切換“下一位置”為“當前位置”,如此重複直至到達出口;若當前位置“不可通”,則應順著“來向”退回到“前一通道塊”,然後朝著除“來向”之外的其他方向繼續探索;若該通道塊的四周4個方塊均“不可通”,則應從“當前路徑”上刪除該通道塊。所謂“下一位置”指的是當前位置四周4個方向(上、下、左、右)上相鄰的方塊。假設以棧Stack記錄“當前路徑”,則棧頂中存放的是“當前路徑上最後一個通道塊”。由此,“放入路徑”的操作即為“當前位置入棧”;“從當前路徑上刪除前一通道塊”的操作即為“出棧”。

程式碼塊

maze.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include <cstdlib>
#include <assert.h>
#include <stack>
using namespace std;
#define N 10
struct pos 
{
	size_t _row;
	size_t _col;
};
stack <pos> minstack;
void GetMaze(int arr[][N],int size)
{
	FILE* f = fopen("MAP.txt", "r");
	if (NULL == f){
		cout << "開啟檔案失敗" << endl;
		exit(-1);
	}
	for (int i = 0; i < size; ++i){
		for (int j = 0; j < size;){
			char ch = fgetc(f);
			if (ch == EOF){
				cout << "讀取地圖失敗" << endl;
				exit(-1);
			}
			if (ch == '1' || ch == '0'){
				arr[i][j] = ch - '0';
				++j;
			}
		}
	}
	fclose(f);
}

bool CheckIsAccess(int arr[][N],pos next)
{

	assert(arr);
	if((next._row>=0)&&(next._row<=N)&&(next._col>=0)&&(next._col<=N)&&arr[next._row][next._col]==0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void PrintMaze(int arr[][N],int size)
{

	for (int i=0;i<size;i++)
	{
		for (int j=0;j<size;j++)
		{
			cout<<arr[i][j]<<" ";
		}
		cout<<endl;
	}
	cout<<endl;
}
bool MazePath(int arr[][N],pos entry,stack<pos>& path)
{         //找到通路
	path.push(entry);
	arr[entry._row][entry._col] = 2;
	while (!path.empty())
	{
		pos cur = path.top();
		pos next = cur;
		if (cur._row == N - 1 || cur._row == 0 || cur._col == N - 1 ){       //更新最短路徑
			if (minstack.empty())
				minstack = path;
			else if (path.size() < minstack.size()){
				minstack = path;
				path.pop();
				continue;
			}
		}
		//上
		next._row -= 1;
		if (CheckIsAccess(arr, next)){
			path.push(next);
			arr[next._row][next._col] = 2;
			continue;
		}
		next = cur;
		//下
		next._row += 1;
		if (CheckIsAccess(arr, next)){
			path.push(next);
			arr[next._row][next._col] = 2;
			continue;
		}
		next = cur;
		//左
		next._col -= 1;
		if (CheckIsAccess(arr, next)){
			path.push(next);
			arr[next._row][next._col] = 2;
			continue;
		}
		next = cur;
		//右
		next._col += 1;
		if (CheckIsAccess(arr, next)){
			path.push(next);
			arr[next._row][next._col] = 2;
			continue;
		}
		path.pop();
	}
	if (path.empty())             //判斷是否找完所有路徑
		return true;
	return false;
}
測試程式碼塊:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include <cstdlib>
#include <assert.h>
#include "maze.h"
using namespace std;
#define N 10
int main(){
	int mazeMap[N][N] = { 0 };
	GetMaze(mazeMap, N);
	PrintMaze(mazeMap, N);
	stack<pos> path;
	pos entry = {2,0};        //定義迷宮入口
	bool ret = MazePath(mazeMap,entry,path);
	if (ret){
		PrintMaze(mazeMap, N);
		while (!minstack.empty()){
			cout << "<" << minstack.top()._row << "," << minstack.top()._col << ">" << endl;;
			minstack.pop();
		}
	}
	system("pause");
	return 0;
}

地圖檔案

map.txt

1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
1 1 0 1 0 1 1 1 1 1
1 1 0 1 0 0 0 1 1 1
1 1 0 1 1 1 0 1 1 1
1 1 0 1 1 1 0 1 1 1
1 1 0 0 1 1 0 1 1 1
1 1 1 1 1 1 0 1 1 1
1 1 1 1 1 1 0 1 1 1

執行結果圖