1. 程式人生 > >迷宮問題——回溯法

迷宮問題——回溯法

一、Maze.h

#ifndef __Maze_h__
#define __Maze_h__

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <Windows.h>

#define N 6
#define Initsize 5 //初始儲存空間
#define Increment 2 //每次增量

typedef struct Pos
{
    int row;
    int col;
}Pos;

typedef Pos DataType;

typedef struct
Maze { int maze[N][N]; Pos entry; }Maze; typedef struct Stack { DataType* _array; size_t _size; //有效資料個數 size_t _capacity; //容量 }Stack; void StackInit(Stack *s); void CheckCapacity(Stack* s); void StackPush(Stack* s, DataType x); void StackPop(Stack* s); DataType StackTop(Stack* s); size_t StackSize(Stack* s); void
StackDestroy(Stack* s); void MazeInit(Maze* m); void MazePrint(Maze* m); int MazeCheckIsAccess(Pos pos); void MazeGetPath(Maze* m, Pos entry, Stack *path); void MazeGetShortPath(Maze* m, Pos entry, Stack *path, Stack *shortpath, int flag); #endif __Maze_h__

二、Maze.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Maze.h" //棧初始化 void StackInit(Stack* s) { assert(s); s->_size = 0; s->_capacity = Initsize; s->_array = (DataType*)malloc(Initsize*sizeof(DataType)); assert(s->_array); memset(s->_array, 0, s->_capacity * sizeof(DataType)); } //擴容 void CheckCapacity(Stack* s) { assert(s); if (s->_size >= s->_capacity) { DataType* ptr = (DataType*)realloc(s->_array, (s->_capacity + Increment)*sizeof(DataType)); assert(ptr); s->_array = ptr; s->_capacity += Increment; } } //入棧 void StackPush(Stack* s, DataType x) { assert(s); CheckCapacity(s); s->_array[s->_size] = x; s->_size++; } //出棧 void StackPop(Stack* s) { assert(s); if (s->_size == 0) { return; } else { s->_size--; } } //獲取棧頂元素 DataType StackTop(Stack* s) { assert(s&&s->_size > 0); return s->_array[(s->_size) - 1]; } //棧長度 size_t StackSize(Stack* s) { assert(s); return s->_size; } //銷燬 void StackDestroy(Stack* s) { free(s->_array); s->_size = 0; s->_capacity = 0; } //初始化迷宮 void MazeInit(Maze* m) { assert(m); int a[N][N] = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0 }, { 0, 0, 1, 1, 1, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 1, 1, 0 }, { 0, 0, 1, 0, 0, 0 }, }; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { m->maze[i][j] = a[i][j]; } } m->entry.row = 5; m->entry.col = 2; } //列印迷宮 void MazePrint(Maze* m) { assert(m); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%d ", m->maze[i][j]); } printf("\n"); } printf("\n"); } //判斷是否為出口,假設出口在最後一列 int MazeCheckIsAccess(Pos pos) { if (pos.col == N - 1) { return 1; } return 0; } //單通路標記 void MarkPath(Maze** pm, Pos entry) { (*pm)->maze[entry.row][entry.col] = 2; } //尋找單通路——只能處理單條路徑 void MazeGetPath(Maze* m, Pos entry, Stack *path) { assert(m); if (entry.row < 0 || entry.row >= N || entry.col < 0 || entry.col >= N) //座標不合法,直接返回 { return; } if (m->maze[entry.row][entry.col] == 1) //如果是路,就入棧,並進行標記 { StackPush(path, entry); MarkPath(&m, entry); } else //否則,直接返回 { return; } if (MazeCheckIsAccess(entry)) //判斷是否到達出口 { printf("找到出口!\n"); printf("出口座標:%d %d\n", StackTop(path).row, StackTop(path).col); printf("路徑長度為:%d\n", StackSize(path)); printf("路徑為:"); for (int i = 0; i < (int)path->_size; i++) { printf("(%d,%d) ", path->_array[i].row, path->_array[i].col); } printf("\n"); StackPop(path); //通路上其他非出口位置是經4個方向都找過後才Pop並返回上一位置;而出口位置是不需要查詢4個方向,直接Pop並返回上一位置 MazePrint(m); return; } //如果沒有找到出口,分別在當前位置的4個方向繼續尋找 //上 Pos up_pos = entry; up_pos.row--; MazeGetPath(m, up_pos, path); //下 Pos down_pos = entry; down_pos.row++; MazeGetPath(m, down_pos, path); //左 Pos left_pos = entry; left_pos.col--; MazeGetPath(m, left_pos, path); //右 Pos right_pos = entry; right_pos.col++; MazeGetPath(m, right_pos, path); StackPop(path); return; } //複製棧 void StackCopy(Stack *src, Stack *dst) { assert(src&&dst); if (src->_size == 0) { dst->_size = 0; } else { if (dst->_capacity < src->_size) { DataType *ptr = (DataType *)realloc(dst->_array, src->_size*sizeof(DataType)); assert(ptr); dst->_array = ptr; dst->_capacity = src->_size; } dst->_size = src->_size; memcpy(dst->_array, src->_array, sizeof(DataType)*src->_size); } } //標記通路 void MarkPath1(Maze** pm, Pos entry, int flag) { (*pm)->maze[entry.row][entry.col] = flag; } //尋找最短路徑——可處理多條路徑 void MazeGetShortPath(Maze* m, Pos entry, Stack *path, Stack *shortpath, int flag) { assert(m); if (entry.row < 0 || entry.row >= N || entry.col < 0 || entry.col >= N) //座標不合法,直接返回 { return; } if (m->maze[entry.row][entry.col] == 1 || m->maze[entry.row][entry.col]>flag) //如果是路或者有更短的路,就入棧,並進行標記 { StackPush(path, entry); MarkPath1(&m, entry, flag++); } else //否則,直接返回 { return; } if (MazeCheckIsAccess(entry)) //判斷是否到達出口 { printf("找到出口!\n"); printf("出口座標:%d %d\n", StackTop(path).row, StackTop(path).col); printf("路徑長度為:%d\n", StackSize(path)); printf("路徑為:"); for (int i = 0; i < (int)path->_size; i++) { printf("(%d,%d) ", path->_array[i].row, path->_array[i].col); } printf("\n"); if (StackSize(shortpath) == 0 || StackSize(path) < StackSize(shortpath)) { StackCopy(path, shortpath); //儲存最短路徑 } StackPop(path); //通路上其他非出口位置是經4個方向都找過後才Pop並返回上一位置;而出口位置是不需要查詢4個方向,直接Pop並返回上一位置 MazePrint(m); return; } //如果沒有找到出口,分別在當前位置的4個方向繼續尋找 //上 Pos up_pos = entry; up_pos.row--; MazeGetShortPath(m, up_pos, path, shortpath, flag); //下 Pos down_pos = entry; down_pos.row++; MazeGetShortPath(m, down_pos, path, shortpath, flag); //左 Pos left_pos = entry; left_pos.col--; MazeGetShortPath(m, left_pos, path, shortpath, flag); //右 Pos right_pos = entry; right_pos.col++; MazeGetShortPath(m, right_pos, path, shortpath, flag); StackPop(path); return; }

三、Test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Maze.h"

int main()
{
    Maze m;
    MazeInit(&m);
    MazePrint(&m);

    Stack path;
    Stack shortpath;
    StackInit(&path);
    StackInit(&shortpath);

    MazeGetShortPath(&m, m.entry, &path, &shortpath, 1);

    printf("最短路徑長度為:%d\n", StackSize(&shortpath));
    printf("路徑為:");
    for (int i = 0; i < (int)shortpath._size; i++)
    {
        printf("(%d,%d) ", shortpath._array[i].row, shortpath._array[i].col);
    }
    printf("\n");

    StackDestroy(&path);
    StackDestroy(&shortpath);

    system("pause");
    return 0;
}

執行結果:

這裡寫圖片描述