一、问题描述
根据输入的长和宽随机生成一个迷宫,随机生成或者输入一个起点和一个终点,运用广度优先搜索算法,找到这个迷宫中起点到终点的最短路径,并输出结果。
二、思路与算法
1.根据给定的迷宫长和宽创建一个动态数组,初始化数组并随机生成一个迷宫,再随机生成或者输入一个起点和一个终点。
2.设置一个结构体Node,其中包括点的坐标,以及五个指针:front(用于后期回溯得出的最短路径)、left、right、up、down。将起点和终点存入Node,从起点开始分别遍历其上下左右四个坐标是否有“墙”,若没有,向所查询的方向前进一步,新建一个Node,存入该点。
3.另设置一个结构体Queue,每前进一步,将新的点的指针存入Queue组成的链表,从头到尾遍历这个链表,链表中每个指针所指向的点都会重复步骤2。
4.重复2、3步骤,遍历整个树,以此实现广度搜索算法,直至找到终点。
5.如果找到了终点,则从已存好的终点Node开始,通过指针front一步步还原这个路径,直至走到起点,然后输出这个过程得到最终的最短路径。如果没有找到,则输出“No path.”。
三、C语言实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <Windows.h>
typedef struct Point
{
int arrrow;
int arrcol;
}Point;
typedef struct Node
{
Point point;
struct Node* front;
struct Node* left;
struct Node* right;
struct Node* up;
struct Node* down;
}Node;
typedef struct Queue
{
struct Node* node;
struct Queue* next;
};
struct Node* CreateNode(int row, int col)//长长的链表捏
{
struct Node* node = (struct Node*)malloc(sizeof(struct Node));
node->point.arrrow = row;
node->point.arrcol = col;
node->front = NULL;
node->left = NULL;
node->right = NULL;
node->up = NULL;
node->down = NULL;
return node;
}
struct Queue* CreateQueue(struct Node* addnode)//动态队列记录每层搜索
{
struct Queue* queue = (struct Queue*)malloc(sizeof(struct Queue));
queue->node = addnode;
queue->next = NULL;
return queue;
}
//设置颜色的捏
VOID SetColor(UINT uFore, UINT uBack)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(handle, uFore + uBack * 0x10);
}
//测试,打印全部迷宫
void TextPrint(char** maze, int mazerow, int mazecol)
{
for (int i = 0; i < mazerow; i++)
{
for (int j = 0; j < mazecol; j++)
{
printf("%c", maze[i][j]);
}
printf("\n");
}
printf("\n");
}
//打印整个迷宫捏
void PrintMaze(char** maze, int mazerow, int mazecol)
{
for (int i = 0; i < mazerow; i++)
{
for (int j = 0; j < mazecol; j++)
{
if (maze[i][j] == '=')
printf(" ");
else if (maze[i][j] == '1')
printf(" ");
else if (maze[i][j] == '0')
printf(" ");
else if (maze[i][j] == '-')
printf("---");
else if (maze[i][j] == ' ')
printf(" ");
else if (maze[i][j] == '!')
{
SetColor(4, 0);
printf(" ! ");
SetColor(7, 0);
}
else if (maze[i][j] == '<' || maze[i][j] == '>')
{
SetColor(4, 0);
printf("%c", maze[i][j]);
SetColor(7, 0);
}
else if (maze[i][j] == '*')
{
SetColor(4, 0);
printf(" * ");
SetColor(7, 0);
}
else
printf("%c", maze[i][j]);
}
printf("\n");
}
printf("\n");
}
//初始化迷宫
void InitMaze(char **maze, int mazerow, int mazecol)
{
//初始
for (int i = 0; i < mazerow; i++)
{
for (int j = 0; j < mazecol; j++)
{
maze[i][j] = ' ';
}
}
//拐角
for (int i = 0; i < mazerow; i += 2)
{
for (int j = 0; j < mazecol; j += 2)
{
maze[i][j] = '+';
}
}
//左右墙壁
for (int i = 1; i < mazerow; i += 2)
{
maze[i][0] = '|';
maze[i][mazecol - 1] = '|';
}
//上下墙壁
for (int i = 1; i < mazecol; i += 2)
{
maze[0][i] = '-';
maze[mazerow - 1][i] = '-';
}
}
//随机生成迷宫
void CreateMaze(char **maze, int mazerow, int mazecol, int wallweight)
{
srand((unsigned)time(NULL));
for (int i = 1; i < mazerow; i += 2)
{
for (int j = 2; j < mazecol - 2; j += 2)
{
int randnum = rand() % 10 + 1;
if (randnum <= wallweight)
{
maze[i][j] = '|';
}
else
maze[i][j] = '=';//原本所有通路都是1,为了打印时的美观性,将上下与左右区分
}
}
for (int i = 1; i < mazecol; i += 2)
{
for (int j = 2; j < mazerow - 2; j += 2)
{
int randnum = rand() % 10 + 1;
if (randnum <= wallweight)
{
maze[j][i] = '-';
}
else
maze[j][i] = '1';
}
}
PrintMaze(maze, mazerow, mazecol);
}
//设置起点和终点
Point StartAndEnd(char** maze, int row, int col)
{
/*srand((unsigned)time(NULL)); */
Point point;
int randomrow = rand() % row + 1;
int randomcol = rand() % col + 1;
printf("[%d, %d]\n", randomrow, randomcol);
point.arrrow = randomrow * 2 - 1;
point.arrcol = randomcol * 2 - 1;
return point;
}
//广度优先算法
int BFS(char** maze, Point start, Point end, int mazerow, int mazecol)
{
int row = start.arrrow;
int col = start.arrcol;
struct Node* startnode = CreateNode(row, col);//startnode不能动
row = end.arrrow;
col = end.arrcol;
struct Node* endnode = CreateNode(row, col);
struct Node* tmpnode = startnode;
struct Queue* headqueue = CreateQueue(startnode);
struct Queue* head = headqueue;//便于释放内存
struct Queue* tmpqueue = headqueue;
int flag = 0;
//广度搜索遍历
while (1)
{
row = headqueue->node->point.arrrow;
col = headqueue->node->point.arrcol;
tmpnode = headqueue->node;
maze[row][col] = '0';
if (maze[row][col - 1] == '=' && maze[row][col - 2] != '0')
{
struct Node* node = CreateNode(row, col - 2);
node->front = tmpnode;
tmpnode->left = node;
maze[row][col - 2] = '0';
if (row == end.arrrow && col - 2 == end.arrcol)
{
flag = 1;
endnode = node;
printf("found\n");
break;
}
struct Queue* queue = CreateQueue(node);
tmpqueue->next = queue;
tmpqueue = queue;
}
if (maze[row][col + 1] == '=' && maze[row][col + 2] != '0')
{
struct Node* node = CreateNode(row, col + 2);
node->front = tmpnode;
tmpnode->right= node;
maze[row][col + 2] = '0';
if (row == end.arrrow && col + 2 == end.arrcol)
{
flag = 1;
endnode = node;
printf("found\n");
break;
}
struct Queue* queue = CreateQueue(node);
tmpqueue->next = queue;
tmpqueue = queue;
}
if (maze[row - 1][col] == '1' && maze[row - 2][col] != '0')
{
struct Node* node = CreateNode(row - 2, col);
node->front = tmpnode;
tmpnode->up = node;
maze[row - 2][col] = '0';
if (row - 2 == end.arrrow && col == end.arrcol)
{
flag = 1;
endnode = node;
printf("found\n");
break;
}
struct Queue* queue = CreateQueue(node);
tmpqueue->next = queue;
tmpqueue = queue;
}
if (maze[row + 1][col] == '1' && maze[row + 2][col] != '0')
{
struct Node* node = CreateNode(row + 2, col);
node->front = tmpnode;
tmpnode->down = node;
maze[row + 2][col] = '0';
if (row + 2 == end.arrrow && col == end.arrcol)
{
flag = 1;
endnode = node;
printf("found\n");
break;
}
struct Queue* queue = CreateQueue(node);
tmpqueue->next = queue;
tmpqueue = queue;
}
if (headqueue->next == NULL)
{
flag = 0;
printf("No path...\n");
break;
}
headqueue = headqueue->next;
}
//如果找到,回溯路线
if (flag)
{
//测试
TextPrint(maze, mazerow, mazecol);
flag = 0;
tmpnode = endnode;
while (1)
{
row = tmpnode->point.arrrow;
col = tmpnode->point.arrcol;
maze[row][col] = '*';
tmpnode = tmpnode->front;
if (tmpnode == NULL)
break;
if (tmpnode->left == endnode)
{
maze[row][col + 1] = '<';
}
else if (tmpnode->right == endnode)
{
maze[row][col - 1] = '>';
}
else if (tmpnode->up == endnode)
{
maze[row + 1][col] = '!';
}
else if (tmpnode->down == endnode)
{
maze[row - 1][col] = '!';
}
endnode = endnode->front;
flag++;
}
}
tmpqueue = head;
while (tmpqueue != NULL)
{
tmpqueue = tmpqueue->next;
free(head->node);
free(head);
head = tmpqueue;
}
return flag;
}
int main()
{
//输入行和列
int row = 0, col = 0;
printf("please input row(行)and col(列):\n");
scanf("%d %d", &row, &col);
if (!(row > 0 && col > 0))
{
printf("input ERROR\n");
return 1;
}
int wallweight = 0;
printf("please input the weight of wall(1 ~ 10, less than 4 best):\n");
scanf("%d", &wallweight);
if (!(wallweight > 0 && wallweight <= 10))
{
printf("input ERROR\n");
return 1;
}
//创建一个动态数组
int mazerow = row * 2 + 1;
int mazecol = col * 2 + 1;
char **maze = (char**)calloc(mazerow, sizeof(char*));
if (maze == NULL)
{
printf("malloc ERROR\n");
return 1;
}
for (int i = 0; i < mazerow; i++)
{
maze[i] = (char*)calloc(mazecol, sizeof(char));
if (maze[i] == NULL)
{
printf("malloc ERROR\n");
return 1;
}
}
//初始化迷宫
InitMaze(maze, mazerow, mazecol);
//随机生成迷宫
int x = 0;
do
{
CreateMaze(maze, mazerow, mazecol, wallweight);
printf("Reset the maze? Yes(1)/No(0)\n");
scanf("%d", &x);
} while (x);
//设置起点和终点
int choice = 0;
Point start;
Point end;
printf("Random point(1) OR Input point(0)\n");
scanf("%d", &choice);
if (choice == 1)
{
start = StartAndEnd(maze, (int)(row / 2), (int)(col / 2));
end = StartAndEnd(maze, row, col);
}
else if (choice == 0)
{
int row = 0;
int col = 0;
printf("Please input startpoint row col\n");
scanf("%d %d", &row, &col);
start.arrrow = row * 2 - 1;
start.arrcol = col * 2 - 1;
printf("Please input endpoint row col\n");
scanf("%d %d", &row, &col);
end.arrrow = row * 2 - 1;
end.arrcol = col * 2 - 1;
}
else
{
printf("Input ERROR\n");
return -1;
}
//广度优先算法
int flag = BFS(maze, start, end, mazerow, mazecol);
//输出结果
if (flag)
{
PrintMaze(maze, mazerow, mazecol);
printf("step = %d\n", flag);
}
//释放内存
for (int i = 0; i < mazerow; i++)
{
free(maze[i]);
}
free(maze);
return 0;
}