(C++)資料結構實驗二——迷宮問題
BFS演算法迷宮
#include <iostream>
#include <string>
//#include <queue>
#include "QueueBottom.h"
#include <fstream>
using namespace std;
#include <iomanip>
#include <Windows.h>
#include <time.h>
clock_t start,finish;
//改變字型顏色
void setColour(int x){
HANDLE h = GetStdHandle (-11);
SetConsoleTextAttribute(h,x);
}
//四個方向
int maze[100][100], past_footprint[100][100];
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
//儲存最終的路徑的陣列
int final_array[100][100];
int printmaze[100][100];
int second_printmaze[100][100];
int whole_step;
struct point
{
int x;
int y;
int step;
};
queue<point> now_footprint;
queue<point> second_footprint;
void printMaze(int& endx, int& endy, int& startx, int& starty, int& length, int& width, string mapname)
{
ifstream first(mapname, ios::in);
if (!first.is_open())
{
cout << "Error: opening file fail" << endl;
system("pause");
exit(1);
}
while (!first.eof())
{
first >> length >> width ;
for (int i = 0; i < length; i++)
for (int j = 0; j < width; j++)
first >> maze[i][j];
first >> endx >> endy >> startx >> starty;
}
// //之後可以改成從txt檔案中讀取
// //輸入豎向長度x
// cout << "Please Enter the length of maze:" << endl;
// cin >> length ;
// //輸入橫向長度y
// cout << "Please Enter the width of maze:" << endl;
// cin >> width ;
// //輸入迷宮的形狀,1為通路,2為障礙,沒有邊框
// cout << "Enter the whole maze:" << endl;
// for (int i = 0; i < length; i++)
// for (int j = 0; j < width; j++)
// cin >> maze[i][j];
// //輸入迷宮的起點
// cout << "Please Enter the start of maze" << endl;
// cin >> endx >> endy ;
// //輸入迷宮的終點
// cout << "Please Enter the end of maze" << endl;
// cin >> startx >> starty ;
}
void findRoad(int startx, int starty, int endx, int endy, int length, int width)
{
//BFS
//隊首元素初始化
point start;
start.x = startx;
start.y = starty;
start.step = 0;
int tag = 1;
now_footprint.push(start);
past_footprint[startx][starty] = 1;
cout << "The Map before function :" << endl;
cout << " 1 for road; 2 for wall " << endl << endl;
for(int m = 0; m < length;m++)
{
for(int n = 0; n < width;n++)
{
cout << maze[m][n] << " ";
}
cout << endl;
}
cout << endl;
//終點標誌
int flag = 0;
while(!now_footprint.empty())
{
//將該佇列的首元素的 x y 分別賦予臨時的 x y
int x = now_footprint.front().x;
int y = now_footprint.front().y;
//判斷該佇列的元素是否與終點匹配
printmaze[x][y] = now_footprint.front().step;
whole_step = now_footprint.front().step;
if(x==endx && y==endy)
{
flag = 1;
cout << "The shortest road from start to end is : "<< now_footprint.front().step << endl ;
cout << "It start at "<< startx << " " << starty << endl;
cout << "It end at " << endx << " " << endy << endl;
cout << "It start with number 0 and end with number " <<now_footprint.front().step << endl;
break;
}
//探路擴充迴圈
for(int k = 0; k <= 3; k++)
{
//建立臨時變數tx ty
int tx,ty;
//按下 右 上 左的順序去探路
tx = x + dx[k];
ty = y + dy[k];
if(maze[tx][ty] == 1 && past_footprint[tx][ty] == 0)
{
//若地點為未探索的點,則建立一個臨時變數temp,將它入隊
point temp;
temp.x = tx;
temp.y = ty;
temp.step = now_footprint.front().step + 1;
now_footprint.push(temp);
//並設定為已訪問
past_footprint[tx][ty] = 1;
}
}
//將已經擴充完的首節點出隊
now_footprint.pop();
}
//若找不到終點,則返回no answer
if (flag == 0)
cout << "No answer" << endl;
//將出口置為特殊符號
//因為我的vscode會亂碼所以只能暫時改成顏色識別符號 :D
setColour(12);
cout << setw(4) <<"#";
setColour(15);
cout << endl;
for(int m = 0; m < length;m++)
{
for(int n = 0; n < width;n++)
{
//需要包含標頭檔案iomanip
//讓每一個輸出的寬度都為4
cout<<setw(4)<<printmaze[m][n];
//下面這行程式碼可以使得輸出的字元左對齊
//<<setiosflags(ios::left)
//cout << printmaze[m][n] << " ";
}
cout << endl;
}
cout << endl;
}
void again_findRoad(int startx, int starty, int endx, int endy, int length, int width)
{
for(int i = 0; i <= length; i++)
for(int j = 0; j <= width; j++)
past_footprint[i][j] = 0;
point start;
start.x = endx;
start.y = endy;
start.step = 0;
int printmaze[100][100];
int tag = 1;
second_footprint.push(start);
past_footprint[endx][endy] = 1;
int flag = 0;
while(!second_footprint.empty())
{
int x = second_footprint.front().x;
int y = second_footprint.front().y;
second_printmaze[x][y] = second_footprint.front().step;
if(x==startx && y==starty)
{
flag = 1;
cout << "The shortest road from start to end is : "<< second_footprint.front().step << endl ;
cout << "It start at "<< endx << " " << endy << endl;
cout << "It end at " << startx << " " << starty << endl;
cout << "It start with number 0 and end with number " <<second_footprint.front().step << endl;
break;
}
for(int k = 0; k <= 3; k++)
{
int tx,ty;
tx = x + dx[k];
ty = y + dy[k];
if(maze[tx][ty] == 1 && past_footprint[tx][ty] == 0)
{
point temp;
temp.x = tx;
temp.y = ty;
temp.step = second_footprint.front().step + 1;
second_footprint.push(temp);
past_footprint[tx][ty] = 1;
}
}
second_footprint.pop();
}
cout << endl;
for(int m = 0; m < length;m++)
{
for(int n = 0; n < width;n++)
{
cout<<setw(4)<<second_printmaze[m][n];
}
cout << endl;
}
cout << endl;
}
void print_final_road(int length, int width, int step)
{
//step = whole_step;
for(int m = 0; m < length;m++ )
for(int n = 0; n < width;n++ )
{
if(printmaze[m][n] + second_printmaze[m][n] == step)
{
final_array[m][n] = 1;
}
}
for(int m = 0; m < length; m++ )
{
for(int n = 0; n < width; n++ )
{
// final_array[m][n] = printmaze[m][n] + second_printmaze[m][n] ;
cout << setw(4) << final_array[m][n];
}
cout << endl;
}
}
int main()
{
//定義變數
string mapname;
int endx, endy, startx, starty, width, length, afterendx, afterendy, aftertag;
//選擇地圖的號碼
int tag;
while(1)
{
cout << "Please Choose the Map of CityPark : "<< endl;
cout << "Press 0 to exit" << endl;
cout << "-1:ClearScreen 0:Exit" << endl;
cout << "1:Shenzhen 2:GuangZhou " << endl;
cout << "3:BeiJing 4:ShangHai " << endl;
cin >> tag;
cout << endl;
switch (tag)
{
case 1:
{
/*要計算時間的程式碼*/
mapname = "ShenZhenMap.txt";
printMaze(endx, endy, startx, starty, length, width, mapname);
start=clock();
findRoad(endx, endy, startx, starty, length, width);
again_findRoad(endx, endy, startx, starty, length, width);
finish=clock();
print_final_road(length,width,whole_step);
double totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
cout<<"\ntime cost: "<<totaltime<<"seconds!"<<endl;
break;
}
case 2:
{
mapname = "GuangZhouMap.txt";
printMaze(endx, endy, startx, starty, length, width, mapname);
findRoad(endx, endy, startx, starty, length, width);
again_findRoad(endx, endy, startx, starty, length, width);
print_final_road(length,width,whole_step);
break;
}
case 3:
{
mapname = "BeiJingMap.txt";
printMaze(endx, endy, startx, starty, length, width, mapname);
findRoad(endx, endy, startx, starty, length, width);
again_findRoad(endx, endy, startx, starty, length, width);
print_final_road(length,width,whole_step);
break;
}
case 4:
{
mapname = "ShangHaiMap.txt";
printMaze(endx, endy, startx, starty, length, width, mapname);
findRoad(endx, endy, startx, starty, length, width);
again_findRoad(endx, endy, startx, starty, length, width);
print_final_road(length,width,whole_step);
break;
}
case 0:
{
cout << "Exit" << endl;
system("pause");
exit(1);
}
case -1:
{
system("cls");
break;
}
default:
break;
}
}
// printMaze(endx, endy, startx, starty, length, width);
// findRoad(endx,endy,startx,starty,length,width);
system("pause");
return 0;
}
BFS演算法迷宮
#include<iostream>
using namespace std;
#include <time.h>
//地圖陣列,用來儲存迷宮
int map[50][50];
bool visit[50][50];
int ans[250];
int res[250];
int tmp[250];
int k,Min,len;
//以下為增加內容
#include <fstream>
int length, width, startx, starty, endx, endy;
string mapname;
//判斷方向的陣列
int X[4]={-1,1,0,0};
int Y[4]={0,0,-1,1};
clock_t start,finish;
void readTxt(string mapname)
{
ifstream first(mapname, ios::in);
if (!first.is_open())
{
cout << "Error: opening file fail" << endl;
system("pause");
exit(1);
}
while (!first.eof())
{
first >> length >> width ;
for (int i = 0; i < length; i++)
for (int j = 0; j < width; j++)
{
first >> map[i][j];
visit[i][j]=false;
}
first >> startx >> starty >> endx >> endy ;
}
}
void dfs(int startx,int starty,int step,int k){
int x = startx;
int y = starty;
//判斷當前格子的xy是否在0~5範圍內
//若否則直接返回
//這個判斷條件可以防止邊界越界的情況 如x = -1, y = 0
if(x>=length||x<0||y>=width||y<0)return;
//當該點走過,則退出該層遞迴
if(visit[x][y])return;
//當該點為牆,則退出該層遞迴
if(map[x][y]==1)return;
//當xy為終點座標時執行
if(x==endx&&y==endy){
if(step<Min){
ans[k]=x*10+y;
//將步數用Min儲存,用於下次第二次通路的長度比較
Min=step;
for(int i=0;i<=k;i++){
res[i]=ans[i];
}
//全域性變數,用於列印路徑
len=k;
}
return;
}
//將走過的地方置為true
visit[x][y]=true;
ans[k]=x*10+y;
//使用遞迴來判斷某一方向是否能走
for(int i=0;i<4;i++){
dfs(x+X[i],y+Y[i],step+1,k+1);
}
//注意此語句非常關鍵,既然找最短,則就需要不斷 回溯,因此需要將原來訪問過的標記清除
visit[x][y]=false;
//回溯的時候置空,還原
//當回溯到有分叉路的地方的時候,會走for迴圈中沒有走過的路,同時不會影響這次的尋路
//新增該語句後就能從兩條路線中選出相對較短的一條
}
int main(){
//cin >> length >> width >>startx >> starty >> endy >> endx;
//設定一個極大的值,使得第一次必然進入if迴圈
Min = 9999;
//存入輸入的地圖
// for(int i=0;i<length;i++){
// for(int j=0;j<width;j++){
// cin>>map[i][j];
// visit[i][j]=false;
// }
// }
readTxt("BeiJingMap.txt");
//dfs執行
start=clock();
dfs(startx,starty,1,0);
finish=clock();
//列印地圖
for (int i = 0; i < length; i++)
{
for (int j = 0; j < width; j++)
{
cout << map[i][j] << " ";
}
cout << endl;
}
cout << endl;
//輸出res中儲存的座標
for(int i=0;i<=len;i++){
cout<<"("<<res[i]%10<<", "<<res[i]/10<<")"<< "->" ;
if(i % 5 == 0)
cout << endl;
}
double totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
cout<<"\ntime cost: "<<totaltime<<"seconds!"<<endl;
system("pause");
return 0;
}
/*
10 10
0 1 0 0 0 0 0 0 0 0
0 1 0 1 1 1 0 1 1 0
0 1 0 1 0 1 0 1 0 0
0 1 0 1 0 1 0 1 0 0
0 1 0 0 0 1 0 1 1 1
0 1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 1 0 1 1 1 0 1 1 0
0 1 0 0 0 1 0 0 1 0
0 1 1 1 1 1 0 1 1 0
0 0
9 9
*/
1.兩個迷宮均要在當前目錄下建立txt檔案
BFS是以1和2組成迷宮
DFS是以0和1組成迷宮
2.DFS沒有使用stack而只是使用了陣列,BFS中使用了queue,同時實現了底層。
程式碼如下
QueueBottom.h
#include <iostream>
using namespace std;
//模板結構體,可以適用於任何型別
template <typename T>
struct node{
T data;
node *next;
//建構函式初始化next和data值
node(){
next=NULL;
}
//new建立node結點的時候可以選擇是否有初值
node(T x){
data=x;
next=NULL;
}
};
//模板類,可以適用於任何型別
template <typename T>
class queue{
private :
node<T> *head,*tail;
int len=0;
public :
queue(){
node<T> *temp=new node<T>();
head=tail=temp;
len=0;
}
//Q.size(); 返回該佇列的長度
int size(){
return len;
}
//Q.empty(); 返回該佇列是否為空
bool empty(){
if(len==0) return true;
return false;
}
//頭元素
T& front(){
if(len) return head->next->data;
}
//尾元素
T& back(){
if(len) return tail->data;
}
void pop(){
if(len) {
head=head->next;
len--;
}
}
void push(const T a){
node<T> *temp=new node<T>(a);
tail->next=temp;
//?
tail = temp;
temp = NULL;
len++;
}
};
// int main(){
// // Queue<string> Q;
// // Q.push(string("abc1"));
// // Q.push(string("abc2"));
// // Q.push(string("abc3"));
// // cout<<Q.front()<<endl;
// // cout<<Q.back()<<endl;
// // Q.pop();
// // cout<<Q.front()<<endl;
// // cout<<Q.back()<<endl;
// system("pause");
// return 0;
// }
相關文章
- 迷宮問題【資料結構實驗報告】資料結構
- 【dawn·資料結構】迷宮問題(C++)資料結構C++
- 回溯法求迷宮問題
- POJ3984-迷宮問題
- c++迷宮問題回溯法遞迴演算法C++遞迴演算法
- 華為優招面試題---迷宮問題面試題
- 回溯法解決迷宮問題
- 解密迷宮問題:三種高效演算法Java實現,讓你輕鬆穿越未知迷宮解密演算法Java
- C++實現迷宮的生成與解決C++
- 回溯和遞迴實現迷宮問題(C語言)遞迴C語言
- 用C語言解決迷宮問題C語言
- C++基於控制檯的迷宮實現(上)C++
- 迷宮問題——最短程式碼,不到70行
- 資料結構實驗 二維矩陣的實現資料結構矩陣
- 走迷宮
- 洛谷 p1605 迷宮問題 詳解
- 使用A*演算法解迷宮最短路徑問題演算法
- 資料結構實驗(4)資料結構
- 資料結構實驗1資料結構
- 【資料結構】二叉樹(c++)資料結構二叉樹C++
- 資料結構實驗之連結串列二:逆序建立連結串列資料結構
- 用python深度優先遍歷解迷宮問題Python
- 資料結構上機實驗3——圖——外賣成本最優問題資料結構
- 509迷宮
- 資料結構實驗——二叉樹的常見操作資料結構二叉樹
- 我花了一夜用資料結構給女朋友寫個H5走迷宮遊戲資料結構H5遊戲
- 資料結構實驗課五-1資料結構
- 資料結構 - 單連結串列 C++ 實現資料結構C++
- 【資料結構】實現單連結串列(c++)資料結構C++
- 資料結構實驗六是否同一顆二叉樹資料結構二叉樹
- 資料結構 實驗六(二叉排序樹字元統計)資料結構排序字元
- 資料結構實驗之圖論二:圖的深度遍歷資料結構圖論
- dfs深度優先搜尋解決迷宮類問題(遍歷)
- 資料結構實驗三:線性表綜合實驗資料結構
- 03.Java資料結構問題Java資料結構
- 資料結構括號匹配問題資料結構
- 【資料結構】停車場問題資料結構
- 資料結構——RMQ(ST表)問題資料結構MQ