/**
2019年6月数据结构课程设计
迷宫问题求解(三维)
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <windows.h>
#include <queue>
#define MAX_SIZE 100
using namespace std;
struct Node
{
int x; //当前坐标
int y;
int z;
int prex; //前置坐标
int prey;
int prez;
int step; //步数
};
char Map[MAX_SIZE][MAX_SIZE][MAX_SIZE]; //存迷宫图
int Vis[MAX_SIZE][MAX_SIZE][MAX_SIZE]; //标记迷宫是否走过
Node Path[MAX_SIZE][MAX_SIZE][MAX_SIZE]; //记录最短路径
class Maze //迷宫类
{
private: //迷宫参数
int L;//层数
int R;//行数
int C;//列数v
int strx; //"S"坐标位置
int stry;
int strz;
int endx;//“E”坐标位置
int endy;
int endz;
int FLAG;//标记是否能通过
int Minstep;//最小步数
public:
int Deposit;//判断是否存图
bool BFS();//广度优先遍历
void Ret_Maze();//初始化迷宫
void Show_Maze();//显示迷宫
void Get_Point(int &x, int &y, int &z);//获取终点“E”坐标位置
void Print_Path(int x, int y, int z);//输出路径
};
void Maze::Get_Point(int &x, int &y, int &z)//以引用为变量赋值
{
x = this->endx;
y = this->endy;
z = this->endz;
}
bool Maze::BFS()//广度优先遍历算法
{
if (Deposit){
int next[6][3] = {{0, 0, 1}, {0, 0, -1}, {0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}};//每六个为一组,对应x,y,z轴
Node head,tail;//队头,队尾
head.x = strx;//队头初始化为“S”坐标位置
head.y = stry;
head.z = strz;
head.step = 0;
Path[strx][stry][strz].x = strx;
Path[strx][stry][strz].y = stry;
Path[strx][stry][strz].z = strz;
queue<Node> q;//创建队列
q.push(head);//初始队头进队
while(!q.empty()) {//循环队列
head = q.front();//队头等于第组元素
q.pop();//出队
if (head.x == endx && head.y == endy && head.z == endz){//若到达终点
FLAG = 1;//标记更新
Minstep = head.step;//最短步数更新
break;
}
for (int i = 0; i < 6; i++){//遍历六个方向
tail.x = head.x + next[i][0];
tail.y = head.y + next[i][1];
tail.z = head.z + next[i][2];
if (Map[tail.x][tail.y][tail.z] == '#' || tail.x < 0 || tail.x >= L || tail.y < 0 || tail.y >= R || tail.z < 0 || tail.z >= C){//判断是否越界
continue;
}
if ((Map[tail.x][tail.y][tail.z] == '.' || Map[tail.x][tail.y][tail.z] == 'E') && Vis[tail.x][tail.y][tail.z] == 0){//可行进
Path[tail.x][tail.y][tail.z].x = tail.x;//更新当前坐标和前置坐标
Path[tail.x][tail.y][tail.z].y = tail.y;
Path[tail.x][tail.y][tail.z].z = tail.z;
Path[tail.x][tail.y][tail.z].prex = head.x;
Path[tail.x][tail.y][tail.z].prey = head.y;
Path[tail.x][tail.y][tail.z].prez = head.z;
Vis[tail.x][tail.y][tail.z] = 1;//标记更新
tail.step = head.step + 1;//步数更新
q.push(tail);//此点入队
}
}
}
if (FLAG){//迷宫可连通
cout << "You can make it through the maze, the shortest path is " << Minstep << " steps" << endl;
return true;
} else {
cout << "This maze has no access!\n" << endl;
return false;
}
}
else {
cout << "未存入迷宫!" << endl;
}
}
void Maze::Ret_Maze()//初始化迷宫
{
cout << "请输入迷宫数据(层数 行数 列数,有效数据均大于0,起点:“S” 终点:“E” 障碍:“#” 通路:“.”)\n";
cin >> L >> R >> C;//层行列
FLAG = 0;
Minstep = 0;
memset(Map, 0, sizeof(Map));//每次初始化必须重置
memset(Vis, 0, sizeof(Vis));
if (L == 0 || R == 0 || C == 0){//数据为0无意义
cout << "数据错误!\n" ;
return ;
} else {//存图
cout << "请输入存图方式:1.手动存图 2.随机存图\n";
int number;
cin >> number;
if (number == 1){
for (int i = 0; i < L; i++){
for (int j = 0; j < R; j++){
for (int k = 0; k < C; k++){
cin >> Map[i][j][k];
if (Map[i][j][k] == 'S'){
this->strx = i;
this->stry = j;
this->strz = k;
}
if (Map[i][j][k] == 'E'){
this->endx = i;
this->endy = j;
this->endz = k;
}
}
}
}
}
else {
int random;
for (int i = 0; i < L; i++){
for (int j = 0; j < R; j++){
for (int k = 0; k < C; k++){
random = rand() % 2;
if (random){
Map[i][j][k] = '#';
} else {
Map[i][j][k] = '.';
}
}
}
}
cout << "请输入起点和终点坐标:" << endl;
int x, y, z;
cin >> x >> y >> z;
this->strx = x;
this->stry = y;
this->strz = z;
Map[x][y][z] = 'S';
cin >> x >> y >>z;
this->endx = x;
this->endy = y;
this->endz = z;
Map[x][y][z] = 'E';
}
}
Vis[strx][stry][strz] = 1;
cout << "存图成功!\n";
Deposit = 1;
}
void Maze::Show_Maze()//显示迷宫
{
if (Deposit){
int L = this->L;//获取层、行、列数目
int R = this->R;
int C = this->C;
for (int i = 0; i < L; i++){//遍历输出图
for (int j = 0; j < R; j++){
for (int k = 0; k < C; k++){
if (Map[i][j][k] == '#'){
cout << "■";
} else if (Map[i][j][k] == '.'){
cout << "□";
} else{
cout << Map[i][j][k];
}
}
cout << endl;
}
cout << "第" << i+1 << "层" << endl << endl;
}
}
else {
cout << "未存入迷宫!\n";
}
}
void Maze::Print_Path(int x, int y, int z)//路径输出
{
if(Deposit){
if(x == strx && y == stry && z == strz){//到达起点
cout << "(" << Path[strx][stry][strz].y << "," << Path[strx][stry][strz].z << "," << Path[strx][stry][strz].x << ")" << endl;
return ;
}
int px = Path[x][y][z].prex;//倒序输出
int py = Path[x][y][z].prey;
int pz = Path[x][y][z].prez;
Print_Path(px, py, pz);//回溯
cout << "(" << Path[x][y][z].y << "," << Path[x][y][z].z << "," << Path[x][y][z].x << ")" << endl;
}
else {
cout << "未存入迷宫!" << endl;
}
}
void Menu()//界面函数
{
Maze text;
text.Deposit = 0;//初始化为未存图
while (1){
int Lastx; //终点坐标用于路径输出
int Lasty;
int Lastz;
text.Get_Point(Lastx, Lasty, Lastz); //提取终点坐标
int number;
system("color 78");
system("date/t");
system("time/t");
printf("■■■■■■■■■■■■■■■■■■■■ \n");
printf("■ ■ \n");
printf("■ ■■■■■■■■■■■■■■■■ ■ \n");
printf("■ ■欢迎使用迷宫问题求解系统■ ■ \n");
printf("■ ■■■■■■■■■■■■■■■■ ■ \n");
printf("■ ■ \n");
printf("■■■■■■■■■■■■■■■■■■■■ \n");
printf("\n");
printf("请输入您的选择:\n");
printf("1.存入迷宫 2.显示迷宫 3.输出最短路径 4.退出系统\n");
scanf("%d", &number);
switch(number){
case 1 :system("CLS");text.Ret_Maze();system("pause");break;
case 2 :system("CLS");text.Show_Maze();system("pause");break;
case 3 :system("CLS");text.Show_Maze();printf("以第一个点为坐标原点建立右手直角坐标系(x, y, z):\n");if(text.BFS()){text.Print_Path(Lastx, Lasty, Lastz);}system("pause");break;
case 4 :exit(0);
}
}
}
int main()
{
Menu();
return 0;
}
/*
样例
3 4 5
1
S....
.###.
.##..
###.#
#####
#####
##.##
##...
#####
#####
#.###
####E
3 4 5
1
.....
S###.
.##..
###.#
#####
#####
##.##
##...
#####
#####
#.###
####E
1 3 3
1
S##
#E#
###*/