思路
本题与(DD3 地下迷宫)相似,在地下迷宫的基础上增加了体力值的限制。
当一个矩阵被确定时,青蛙移动的水平位移已经被确定为矩阵的长度,即青蛙水平移动消耗的体力已经被确定了。所以我们只需要考虑上下方向的移动:上下移动的位移越小,则消耗的体力值越少,所以青蛙的体力消耗主要取决于上下位移。同时上下位移越小,青蛙的移动路径越短,所以问题就转化成了:求青蛙离开的最短路径。
与DD3 地下迷宫不同的是,本题找到一条可行路径时不直接一路返回,而是回到关键位置继续搜索其他路径,所以这里的搜索函数不再设置返回值。需要注意的是,返回时要将路径中的位置重新置为 1,以便后续搜索。在搜索期间,若可行路径比minPath短且体力值不小于0,则替换minPath。最终若minPath不为空则进行打印,否则无法逃出迷宫。
代码
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> #include <string.h> //**---------------------------------------------------- #define INIT_SIZE 10 #define EXP_SIZE 10 typedef int* STDataType; typedef struct Stack { STDataType* data; int top; int capacity; }ST; void StackInit(ST* st); void StackPush(ST* st, const STDataType x); void StackPop(ST* st); void StackDestory(ST* st); STDataType StackTopData(const ST* st); bool StackEmpty(const ST* st); void StackInit(ST* st) { st->data = (STDataType*)malloc(INIT_SIZE * sizeof(STDataType)); if (st->data == NULL) { perror("StackInit:"); return; } st->capacity = INIT_SIZE; st->top = 0; } void StackPush(ST* st, const STDataType x) { assert(st); if (st->top == st->capacity) { //expand STDataType* tmp = (STDataType*)realloc(st->data, sizeof(STDataType) * (st->top + EXP_SIZE)); if (tmp != NULL) { st->data = tmp; st->capacity += EXP_SIZE; } else { perror("Expand:"); return; } } st->data[st->top] = x; st->top++; } void StackPop(ST* st) { assert(st); assert(st->top > 0); st->top--; } void StackDestory(ST* st) { free(st->data); st->data = NULL; } STDataType StackTopData(const ST* st) { assert(st); assert(st->top > 0);//不允许栈为空 return st->data[st->top - 1]; } bool StackEmpty(const ST* st) { assert(st); return st->top == 0; } int StackSize(const ST* st) { return st->top; } //**---------------------------------------------------- //以上为栈的接口实现 ST path;//记录路径 ST minPath;//记录最短路径 //打印最短路径 void PrintStack(ST* ps) { ST rPath; StackInit(&rPath); while (!StackEmpty(ps)) { StackPush(&rPath, StackTopData(ps)); StackPop(ps); } StackDestory(ps); while (StackSize(&rPath) > 1) { int* tmp = StackTopData(&rPath); printf("[%d,%d],", tmp[0], tmp[1]); StackPop(&rPath); } int* tmp = StackTopData(&rPath); printf("[%d,%d]", tmp[0], tmp[1]); StackPop(&rPath); StackDestory(&rPath); } //深拷贝栈 void StackCopy(ST* sTDest, ST* sTSour) { StackDestory(sTDest); StackInit(sTDest); sTDest->data = (STDataType*)malloc(sizeof(STDataType) * StackSize(sTSour)); memcpy(sTDest->data, sTSour->data, sizeof(STDataType) * StackSize(sTSour)); sTDest->top = sTSour->top; sTDest->capacity = sTSour->capacity; } //DFS寻找最短路径 void FindPath(int** maze, int row, int col, int x, int y, int p) { int* Pos = (int*)malloc(sizeof(int) * 2); Pos[0] = x; Pos[1] = y; StackPush(&path, Pos); if (x < 0 || x >= row || y < 0 || y >= col || maze[x][y] != 1) { StackPop(&path); return; } if ((x == 0) && (y == col - 1)) { if (p >= 0 && (StackEmpty(&minPath) || StackSize(&path) < StackSize(&minPath))) { StackCopy(&minPath, &path); } } maze[x][y] = 2; FindPath(maze, row, col, x - 1, y, p - 3); FindPath(maze, row, col, x + 1, y, p); FindPath(maze, row, col, x, y - 1, p - 1); FindPath(maze, row, col, x, y + 1, p - 1); maze[x][y] = 1; StackPop(&path); } int main() { int row = 0; int col = 0; int p = 0; scanf("%d %d %d", &row, &col, &p); int** maze = (int**)malloc(sizeof(int*) * row); for (int i = 0; i < row; i++) { maze[i] = (int*)malloc(sizeof(int) * col); } for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { scanf("%d", &maze[i][j]); } } StackInit(&path); StackInit(&minPath); FindPath(maze, row, col, 0, 0, p); if(!StackEmpty(&minPath)) { PrintStack(&minPath); } else { printf("Can not escape!\n"); } for (int i = 0; i < row; i++) { free(maze[i]); maze[i] = NULL; } maze = NULL; return 0; }