这个稍微比迷宫1问题要难了一点,但是大致都是差不多的,只是需要小小的改动一下
这里主要介绍它的注意点:
有多条路但是要找到它的最小路径,还是一样的采用深度优先遍历,递归来实现
1、如果是通道,那是不是走过了就要标记,但是我们找的是最小路径是不是就需要回溯,回溯时就要把标记改为通道1,以防下次就走不通了
2、区分深度拷贝和浅拷贝,代码里也有介绍,minpath = path 浅拷贝,指向了同一块内存空间,当path的内容改变minpath也会改变 ;深度拷贝,path 和 minpath 各占不一样的存储空间,不会互相影响 最好结合代码看
上代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include <stdbool.h>
#include <string.h>
typedef struct path
{
int row;
int col;
}PAT;
/*///////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
typedef PAT STDataType;
typedef struct Stack
{
STDataType* a;
int top;//指向栈顶就是size
int capacity;//容量
}ST;
void StackInit(ST* ps);//初始化
void StackPrint(const ST* ps);//打印
void StackPush(ST* ps, STDataType x);//入栈
void StackDestroy(ST* ps);//销毁
void StackPop(ST* ps);//出栈
STDataType StackTop(const ST* ps);//取栈顶
int StackSize(const ST* ps);//计算栈的元素
//bool StackEmpty(const ST* ps,int* size);
bool StackEmpty(const ST* ps);//判断栈是否为空
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;//也可以给 -1
}
//void StackPrint(const ST* ps)
//{
// assert(ps);
// int i;
// for (i = ps->top - 1; i >= 0; i--)
// {
// printf("%d ", ps->a[i]);
// }
// printf("\n");
//}
void NewStack(ST* ps)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ST* newStack = realloc(ps->a, sizeof(ST) * newcapacity);
if (newStack == NULL)
{
printf("开辟内存失败");
exit(-1);
}
ps->a = newStack;
ps->capacity = newcapacity;
}
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->capacity == ps->top)
{
NewStack(ps);
}
ps->a[ps->top] = x;
ps->top++;
}
void StackPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
if (ps->top > 0)
ps->top--;
}
STDataType StackTop(const ST* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
int StackSize(const ST* ps)
{
assert(ps);
return ps->top;
}
bool StackEmpty(ST* ps)
{
return ps->top == 0;
}
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a); ps->a = NULL;
ps->capacity = ps->top = 0;
}
ST path;//设置全局栈
ST minpath;
void StackCopy(ST* path, ST* pcopy)
{
pcopy->a = (STDataType*)malloc(sizeof(STDataType /* STDataType* */) * path->capacity);
memcpy(pcopy->a,path->a,sizeof(STDataType)*path->top);
pcopy->top = path->top;
pcopy->capacity = path->capacity;
}
/*///////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
//输出路径坐标
void PrintPath(ST* path)
{
ST rPath;
StackInit(&rPath);
while (!StackEmpty(path))
{
StackPush(&rPath, StackTop(path));
StackPop(path);
}
while (StackSize(&rPath)>1)
{
PAT top = StackTop(&rPath);
printf("[%d , %d],", top.row, top.col);
StackPop(&rPath);
}
PAT top = StackTop(&rPath);
printf("[%d , %d]", top.row, top.col);
StackPop(&rPath);
StackDestroy(&rPath);
}
void Print(int** maze, int n, int m)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf(" %d ", maze[i][j]);//输入二维数组的值
}
printf("\n");
}
printf("\n");
}
bool IsPass(int** maze, int n, int m, PAT cur)
{
if (cur.row >= 0 && cur.row < n
&& cur.col >= 0 && cur.col < m
&& maze[cur.row][cur.col] == 1)
{
return true;
}
else
return false;
}
void GetMazePath(int** maze, int n, int m, PAT cur,int p)
{
StackPush(&path, cur);//先入栈
if (cur.row == 0 && cur.col == m - 1)
{
//当 minpath 为空 就把 path 的路径深度拷贝到 minpath 中
//当 path 找到了一条比 minpath 更短的路径时 就把 path 的路径深度拷贝到 minpath 中
if (p>=0 && StackEmpty(&minpath)
|| StackSize(&path) < StackSize(&minpath))
{
StackDestroy(&minpath);//把原来的 minpath 释放以免照成内存泄露
//minpath = path 浅拷贝,指向了同一块内存空间,当path的内容改变minpath也会改变
//深度拷贝,path 和 minpath 各占不一样的存储空间,不会互相影响
StackCopy(&path, &minpath);
}
}
maze[cur.row][cur.col] = 2;
//上
PAT next;
next = cur;
next.row -= 1;
if (IsPass(maze, n, m, next))
{
GetMazePath(maze, n, m, next, p - 3);// 向上移动一个单位消耗3个体力值
}
//下
next = cur;
next.row += 1;
if (IsPass(maze, n, m, next))
{
GetMazePath(maze, n, m, next,p);// 向下不消耗体力值
}
//左
next = cur;
next.col -= 1;
if (IsPass(maze, n, m, next))
{
GetMazePath(maze, n, m, next,p-1); // 水平移动一个单位消耗一个体力值
}
//右
next = cur;
next.col += 1;
if (IsPass(maze, n, m, next))
{
GetMazePath(maze, n, m, next, p - 1);// 水平移动一个单位消耗一个体力值
}
maze[cur.row][cur.col] = 1;// 回溯,恢复公共路径
StackPop(&path);// 如果以上条件都不满足就出栈
}
int main()
{
int n = 0, m = 0,p=0;// p为体力值 水平移动一个单位消耗一个体力值 向上移动一个单位消耗3个体力值 向下不消耗体力值
scanf("%d,%d,%d", &n, &m,&p);
//创建二维数组的行
int** maze = (int**)malloc(sizeof(int*) * n);
for (int i = 0; i < n; i++)
{
//创建二维数组的列
maze[i] = (int*)malloc(sizeof(int) * m);
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
scanf("%d", &maze[i][j]);//输入二维数组的值
}
}
StackInit(&path);//初始化栈
StackInit(&minpath);//初始化栈
PAT InPath = { 0.0 };
GetMazePath(maze, n, m, InPath, p);
if (!StackEmpty(&minpath))
{
Print(maze, n, m);
PrintPath(&minpath);
}
else
{
printf("\n逃离失败!");
}
StackDestroy(&path);
StackDestroy(&minpath);
for (int i = 0; i < n; i++)
{
free(maze[i]);
}
free(maze);
maze = NULL;
}