數(shù)據(jù)結(jié)構(gòu)-棧與隊(duì)列--迷宮問題

問題分析

  • 用一個(gè)二維數(shù)組map表示迷宮的信息弱贼,其中‘0’表示可以通過蒸苇,‘1’表示不可通過**,如下圖:
    在這里插入圖片描述
  • 對于在一個(gè)點(diǎn)上的移動(dòng)方向吮旅,可能是東西南北4方向溪烤,或者8方向味咳,如下圖:
    移動(dòng)方向
  • 用一種方法實(shí)現(xiàn)找到從出口的到入口的路徑。

實(shí)現(xiàn)方法

方向設(shè)置

  • 我們可以先構(gòu)建方向結(jié)構(gòu)offsets檬嘀,用數(shù)組offsets\&move[4]或offsets\&move[8]來表示方向
q move[q].a move[q].b
N -1 0
NE -1 1
E 0 1
SE 1 1
S 1 0
SW 1 -1
W 0 -1
NW -1 -1
  • 代碼如下:
//方向枚舉:東槽驶、西、南鸳兽、北掂铐、東北、東南揍异、西北全陨、西南
enum directions{E,W,S,N,NE,SE,NW,SW};

//表示方向
struct offsets
{
    int a, b;
};

//構(gòu)建移動(dòng)方向move
//設(shè)置方向:選擇4方向還是8方向
offsets *move_set(int num = 4)
{
 /*方向表示表
  ___________________________
 | q | move[q].a | move[q].b |
 -----------------------------
 | N |    -1     |     0     |
 | NE|    -1     |     1     |
 | E |     0     |     1     |
 | SE|     1     |     1     |
 | S |     1     |     0     |
 | SW|     1     |    -1     |
 | W |     0     |    -1     |
 | NW|    -1     |    -1     |
 -----------------------------
 */ 
    offsets* move = new offsets[num];
    if (num == 4||num==8)
    {

        move[N].a = -1;
        move[N].b = 0;

        move[E].a = 0;
        move[E].b = 1;

        move[S].a = 1;
        move[S].b = 0;

        move[W].a = 0;
        move[W].b = -1;
    }
    
    if (num == 8)
    {
        move[NE].a = -1;
        move[NE].b = 1;

        move[SE].a = 1;
        move[SE].b = 1;

        move[SW].a = 1;
        move[SW].b = -1;

        move[NW].a = -1;
        move[NW].b = -1;
    }
    return move;
}

路徑記錄和迷宮地圖設(shè)置

  • 建立一個(gè)Items結(jié)構(gòu),它包括位置坐標(biāo)x和y以及下一次該點(diǎn)的移動(dòng)方向dir衷掷;
  • 迷宮地圖為二維數(shù)組辱姨,手動(dòng)輸入,代碼如下:
//記錄路徑
struct Items
{
    int x, y, dir;
};

//設(shè)置地圖
char** map_set(const int width, const int high)
{

    char** map = new char* [width];
    for (int i = 0; i < width; i++)
    {
        map[i] = new char[high];
    }
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < high; j++)
        {
            cin >> map[i][j];
        }
    }
    return map;
}

尋找路徑

  • 首先我們要用==棧==數(shù)據(jù)結(jié)構(gòu)來記錄路徑信息(stack<Items>*ways)戚嗅,這里之所以用指針是方便后續(xù)傳參雨涛;
  • 同時(shí)我們構(gòu)建一個(gè)==全為零==的二維數(shù)組(char**mark)來記錄是否已經(jīng)通過該點(diǎn),比如通過x=i,y=j的點(diǎn)懦胞,那么mark[i][j]=1替久;
  • 話不多說,直接上代碼:
//尋找路徑
stack<Items>* Path(const int width,const int high,char **map,const char can_pass,const int start_x,const int start_y, const char end_signal,const int move_kind)
{
    /*參數(shù)說明:
    * width:迷宮的長度
    * high:迷宮的寬度
    * **map:二維迷宮的信息
    * can_pass:*map[]中可通過字符
    * start_x:起點(diǎn)橫坐標(biāo)
    * start_y:起點(diǎn)縱坐標(biāo)
    * end_signal:終點(diǎn)字符標(biāo)志
    * move_kind:4方向移動(dòng)或8方向移動(dòng)
    */

    //獲取方向表示
    offsets* move;
    move = move_set(move_kind);

    //記錄走過點(diǎn)的信息
    stack<Items>*ways=new stack<Items>;

    //記錄該點(diǎn)是否走過
    int** mark = new int* [width];
    for (int i = 0; i < width; i++)
    {
        mark[i] = new int[high];
        for (int j = 0; j < high; j++)
        {
            mark[i][j] = 0;
        }
    }

    //獲取起始點(diǎn)
    mark[start_x][start_y] = 1;
    Items temp;
    temp.x = start_x;
    temp.y = start_y;
    temp.dir = E;
    ways->push(temp);
    
    //開始尋找路徑
    while (!ways->empty())
    {
        temp = ways->top();
        ways->pop();

        int i = temp.x, j = temp.y, d = temp.dir;
        while (d < move_kind)
        {
            int g = i + move[d].a, h = j + move[d].b;
            if ((g >= 0 && h >= 0) && (g < width && h < high))
            {
                if (map[g][h] == end_signal)
                {
                    cout << "exist!" << endl;
                    // 存儲(chǔ)最后一次路徑信息
                    Items temp1;
                    temp1.x = i;
                    temp1.y = j;
                    temp1.dir = E;
                    ways->push(temp1);
                    return ways;
                }
                //可以通過躏尉,存儲(chǔ)該點(diǎn)
                if (map[g][h] == can_pass && mark[g][h]==0)
                {
                    mark[g][h] = 1;
                    temp.x = i;
                    temp.y = j;
                    temp.dir = d + 1;
                    ways->push(temp);
                    i = g;
                    j = h;
                    d = E;
                }
                else d++;
            }
            else d++;
        }
    }
    cout << "not exist!" << endl;
    return ways;
}

代碼總覽

#include<iostream>
#include<stack>
using namespace std;

//方向枚舉:東蚯根、西、南醇份、北稼锅、東北、東南僚纷、西北矩距、西南
enum directions{E,W,S,N,NE,SE,NW,SW};

//表示方向
struct offsets
{
    int a, b;
};

//構(gòu)建移動(dòng)方向move
//設(shè)置方向:選擇4方向還是8方向
offsets *move_set(int num = 4)
{
 /*方向表示表
  ___________________________
 | q | move[q].a | move[q].b |
 -----------------------------
 | N |    -1     |     0     |
 | NE|    -1     |     1     |
 | E |     0     |     1     |
 | SE|     1     |     1     |
 | S |     1     |     0     |
 | SW|     1     |    -1     |
 | W |     0     |    -1     |
 | NW|    -1     |    -1     |
 -----------------------------
 */ 
    offsets* move = new offsets[num];
    if (num == 4||num==8)
    {

        move[N].a = -1;
        move[N].b = 0;

        move[E].a = 0;
        move[E].b = 1;

        move[S].a = 1;
        move[S].b = 0;

        move[W].a = 0;
        move[W].b = -1;
    }
    
    if (num == 8)
    {
        move[NE].a = -1;
        move[NE].b = 1;

        move[SE].a = 1;
        move[SE].b = 1;

        move[SW].a = 1;
        move[SW].b = -1;

        move[NW].a = -1;
        move[NW].b = -1;
    }
    return move;
}

//記錄路徑
struct Items
{
    int x, y, dir;
};

//設(shè)置地圖
char** map_set(const int width, const int high)
{

    char** map = new char* [width];
    for (int i = 0; i < width; i++)
    {
        map[i] = new char[high];
    }
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < high; j++)
        {
            cin >> map[i][j];
        }
    }
    return map;
}

//尋找路徑
stack<Items>* Path(const int width,const int high,char **map,const char can_pass,const int start_x,const int start_y, const char end_signal,const int move_kind)
{
    /*參數(shù)說明:
    * width:迷宮的長度
    * high:迷宮的寬度
    * **map:二維迷宮的信息
    * can_pass:*map[]中可通過字符
    * start_x:起點(diǎn)橫坐標(biāo)
    * start_y:起點(diǎn)縱坐標(biāo)
    * end_signal:終點(diǎn)字符標(biāo)志
    * move_kind:4方向移動(dòng)或8方向移動(dòng)
    */

    //獲取方向表示
    offsets* move;
    move = move_set(move_kind);

    //記錄走過點(diǎn)的信息
    stack<Items>*ways=new stack<Items>;

    //記錄該點(diǎn)是否走過
    int** mark = new int* [width];
    for (int i = 0; i < width; i++)
    {
        mark[i] = new int[high];
        for (int j = 0; j < high; j++)
        {
            mark[i][j] = 0;
        }
    }

    //獲取起始點(diǎn)
    mark[start_x][start_y] = 1;
    Items temp;
    temp.x = start_x;
    temp.y = start_y;
    temp.dir = E;
    ways->push(temp);
    
    //開始尋找路徑
    while (!ways->empty())
    {
        temp = ways->top();
        ways->pop();

        int i = temp.x, j = temp.y, d = temp.dir;
        while (d < move_kind)
        {
            int g = i + move[d].a, h = j + move[d].b;
            if ((g >= 0 && h >= 0) && (g < width && h < high))
            {
                if (map[g][h] == end_signal)
                {
                    cout << "exist!" << endl;
                    // 存儲(chǔ)最后一次路徑信息
                    Items temp1;
                    temp1.x = i;
                    temp1.y = j;
                    temp1.dir = E;
                    ways->push(temp1);
                    return ways;
                }
                //可以通過,存儲(chǔ)該點(diǎn)
                if (map[g][h] == can_pass && mark[g][h]==0)
                {
                    mark[g][h] = 1;
                    temp.x = i;
                    temp.y = j;
                    temp.dir = d + 1;
                    ways->push(temp);
                    i = g;
                    j = h;
                    d = E;
                }
                else d++;
            }
            else d++;
        }
    }
    cout << "not exist!" << endl;
    return ways;
}

//打印地圖且在地圖中顯示路徑
void Show_path(const int width,const int high,char** map, stack<Items>* ways)
{
    if (ways->empty())return;
    while (!ways->empty())
    {
        int x = ways->top().x, y = ways->top().y;
        map[x][y] = '@';
        ways->pop();
    }
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < high; j++)
        {
            cout << map[i][j] << "\t";
        }
        cout << "\n";
    }
}

int main()
{
    /*測試數(shù)據(jù):(
    10 10
    #S######.#
    ......#..#
    .#.##.##.#
    .#........
    ##.##.####
    ....#....#
    .#######.#
    ....#.....
    .####.###.
    ....#...G#
    */
    int width, high;
    cout << "輸入迷宮的長和寬:" << endl;
    cin >> width >> high;

    char** map;
    cout << "輸入迷宮信息:" << endl;
    map = map_set(width, high);

    stack<Items>* ways;
    ways = Path(width, high, map, '.', 0, 1, 'G', 4);

    Show_path(width, high, map, ways);

    return 0;
}

上一節(jié):數(shù)據(jù)結(jié)構(gòu)-棧與隊(duì)列--隊(duì)列

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末怖竭,一起剝皮案震驚了整個(gè)濱河市锥债,隨后出現(xiàn)的幾起案子缀雳,更是在濱河造成了極大的恐慌元潘,老刑警劉巖睛约,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件现柠,死亡現(xiàn)場離奇詭異,居然都是意外死亡弧可,警方通過查閱死者的電腦和手機(jī)屎慢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門码倦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸦致,“玉大人潮剪,你說我怎么就攤上這事涣楷。” “怎么了抗碰?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵狮斗,是天一觀的道長。 經(jīng)常有香客問我弧蝇,道長碳褒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任看疗,我火速辦了婚禮沙峻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹃觉。我一直安慰自己专酗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布盗扇。 她就那樣靜靜地躺著,像睡著了一般沉填。 火紅的嫁衣襯著肌膚如雪疗隶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天翼闹,我揣著相機(jī)與錄音斑鼻,去河邊找鬼。 笑死猎荠,一個(gè)胖子當(dāng)著我的面吹牛坚弱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播关摇,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼荒叶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了输虱?” 一聲冷哼從身側(cè)響起些楣,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宪睹,沒想到半個(gè)月后愁茁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亭病,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年鹅很,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罪帖。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡促煮,死狀恐怖邮屁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情污茵,我是刑警寧澤樱报,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站泞当,受9級特大地震影響迹蛤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜襟士,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一盗飒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧陋桂,春花似錦逆趣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至梨州,卻和暖如春痕囱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暴匠。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工鞍恢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人每窖。 一個(gè)月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓帮掉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窒典。 傳聞我的和親對象是個(gè)殘疾皇子蟆炊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容