C语言求解迷宫问题
迷宮問題求解
https://www.nowcoder.com/questionTerminal/cf24906056f4488c9ddb132f317e03bc
以上迷宮OJ題曾經是百度某一年的其中一個筆試題,
迷宮問題本質就是一個圖的遍歷問題,從起點開始不斷四個方向探索,直到走到出口,
走的過程中我們借助棧記錄走過路徑的坐標,棧記錄坐標有兩方面的作用,
一方面是記錄走過的路徑,一方面方便走到死路時進行回溯找其他的通路。
輸入兩個整數,分別表示二維數組的行數,列數。
再輸入相應的數組,其中的1表示墻壁,0表示可以走的路。
數據保證有唯一解,不考慮有多解的情況,即迷宮只有一條通道。
5 5
0 1 0 0 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
題解
關于求解,肯定是先創建一個自身位置的結構體,由于c語言沒有那么多庫函數,所以我們只能自己寫一個棧了
#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool.h> typedef struct Postion {int row;int col; }PT; typedef PT STDataType; // 支持動態增長的棧 typedef struct Stack {STDataType* a;int top; // 棧頂int capacity; // 容量 }Stack, ST; // 初始化棧 void StackInit(Stack* ps); // 入棧 void StackPush(Stack* ps, STDataType data); // 出棧 void StackPop(Stack* ps); // 獲取棧頂元素 STDataType StackTop(Stack* ps); // 獲取棧中有效元素個數 int StackSize(Stack* ps); // 檢測棧是否為空,如果為空返回非零結果,如果不為空返回0 bool StackEmpty(Stack* ps); // 銷毀棧 void StackDestroy(Stack* ps); // 初始化棧 void StackInit(Stack* ps) {assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL){printf("malloc fail\n");exit(-1);}ps->capacity = 4;ps->top = 0; } // 入棧 void StackPush(Stack* ps, STDataType data) {assert(ps);//滿了 -> 擴容if (ps->top == ps->capacity){STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));if (tmp == NULL){printf("realloc fail\n");exit(-1);}else{ps->a = tmp;ps->capacity *= 2;}}ps->a[ps->top] = data;ps->top++; } // 出棧 void StackPop(Stack* ps) {assert(ps);assert(ps->top > 0);ps->top--; } // 獲取棧頂元素 STDataType StackTop(Stack* ps) {assert(ps);assert(ps->top > 0);return ps->a[ps->top - 1]; } // 獲取棧中有效元素個數 int StackSize(Stack* ps) {assert(ps);return ps->top; } // 檢測棧是否為空,如果為空返回非零結果,如果不為空返回0 bool StackEmpty(Stack* ps) {assert(ps);return ps->top == 0; } // 銷毀棧 void StackDestroy(Stack* ps) {assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0; } ///棧寫好之后,就開始進入求解路徑了,首先得創建一個迷宮,獲取迷宮地圖,初始化自身位置,開始上下左右判斷移動,為0表示無障礙,可以走;
這里就可以用遞歸來完成,走過的路要改成除0和1外的數(這里我用2來代替了),不然又會走重;當走到死路時,就需要往回走,回到一個有第二個方向可以走的位置,被稱為回溯,還用到了棧的先進后出,所以用棧來記錄路徑是最好不夠了;
//主函數
int main() {int N = 0, M = 0;while (scanf("%d%d", &N, &M) != EOF){//創建迷宮,獲取迷宮地圖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);PT entry = { 0,0 };if (GetMazePath(maze, N, M, entry)){PrintPath(&Path);}else{printf("沒有找到通路\n");}//銷毀迷宮StackDestroy(&Path);for (int i = 0; i < N; ++i){free(maze[i]);}free(maze);maze = NULL;}return 0; }迷宮最短路徑求解
小青蛙有一天不小心落入了一個地下迷宮,小青蛙希望用自己僅剩的體力值P跳出這個地下迷宮。
為了讓問題簡單,假設這是一個n*m的格子迷宮,迷宮每個位置為0或者1,
0代表這個位置有障礙物,小青蛙達到不了這個位置;1代表小青蛙可以達到的位置。
小青蛙初始在(0,0)位置,地下迷宮的出口在(0,m-1)
(保證這兩個位置都是1,并且保證一定有起點到終點可達的路徑),
小青蛙在迷宮中水平移動一個單位距離需要消耗1點體力值,
向上爬一個單位距離需要消耗3個單位的體力值,向下移動不消耗體力值,
當小青蛙的體力值等于0的時候還沒有到達出口,小青蛙將無法逃離迷宮。
現在需要你幫助小青蛙計算出能否用僅剩的體力值跳出迷宮(即達到(0,m-1)位置)。
本題在曾經是美團某一年的筆試題,
本題在上一個題的基礎上計入了體力值的概念,
但是本題還有一個隱藏條件,就是要找出迷宮的最短路徑,
如下的兩個測試用例,需要找出最短路徑,才能通過全部測試用例
4 4 10 1 0 0 1 1 1 0 1 0 1 1 1 0 0 1 1
10 10 50 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 1 1 0 0 1 0 00 0 0 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 0 0 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 0 0 0 0 0 1 1 0 0 1 1 1 11 1 1
鏈接:https://www.nowcoder.com/questionTerminal/571cfbe764824f03b5c0bfd2eb0a8ddf?f=discussion
題解
同樣的,c語言要自己寫一個棧,和上面是一樣的
#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool.h> #include<string.h> typedef struct Postion {int row;int col; }PT; typedef PT STDataType; // 支持動態增長的棧typedef struct Stack {STDataType* a;int top; // 棧頂int capacity; // 容量 }Stack, ST; // 初始化棧 void StackInit(Stack* ps); // 入棧 void StackPush(Stack* ps, STDataType data); // 出棧 void StackPop(Stack* ps); // 獲取棧頂元素 STDataType StackTop(Stack* ps); // 獲取棧中有效元素個數 int StackSize(Stack* ps); // 檢測棧是否為空,如果為空返回非零結果,如果不為空返回0 bool StackEmpty(Stack* ps); // 銷毀棧 void StackDestroy(Stack* ps); // 初始化棧 void StackInit(Stack* ps) {assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL){printf("malloc fail\n");exit(-1);}ps->capacity = 4;ps->top = 0; } // 入棧 void StackPush(Stack* ps, STDataType data) {assert(ps);//滿了 -> 擴容if (ps->top == ps->capacity){STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));if (tmp == NULL){printf("realloc fail\n");exit(-1);}else{ps->a = tmp;ps->capacity *= 2;}}ps->a[ps->top] = data;ps->top++; } // 出棧 void StackPop(Stack* ps) {assert(ps);assert(ps->top > 0);ps->top--; } // 獲取棧頂元素 STDataType StackTop(Stack* ps) {assert(ps);assert(ps->top > 0);return ps->a[ps->top - 1]; } // 獲取棧中有效元素個數 int StackSize(Stack* ps) {assert(ps);return ps->top; } // 檢測棧是否為空,如果為空返回非零結果,如果不為空返回0 bool StackEmpty(Stack* ps) {assert(ps);return ps->top == 0; } // 銷毀棧 void StackDestroy(Stack* ps) {assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0; } ///
由于加入了體力值這一變量,路徑也就變為不止一條,所以我們還需要初始化一個裝最短路徑的棧,由圖,紫色路徑不能滿足體力要求,故需要尋找最優路徑;
多條路徑之間不能互相干涉,第一條路徑走完后,迷宮就被修改了,為了不影響第二條路徑,我們需要將迷宮恢復成沒走一樣的狀態
如果不恢復的話,第二條路徑無路可走
深淺拷貝問題
//找到了更短的路徑,更新minPathif(p >= 0 && StackEmpty(&minPath)|| StackSize(&Path) < StackSize(&minPath)){//找到更短路徑,更新minPath//minPath=Path;StackDestroy(&minPath);StackCopy(&Path,&minPath);}在c語言中,這里=是直接賦值,就是把它的地址存放數據的地址給你了,如果寫minPath=Pah的話,編譯器提供的就是淺拷貝,再后面釋放內存時,Path已經將那塊空間釋放了,minPath指向的那塊空間已經不是原來的空間了
總結
- 上一篇: 从零开始AlignedReID_05
- 下一篇: 【服务器数据集】中心服务器上存放(下载)