藍橋杯 BFS經典題 —— 卡片換位(單走華容道)

BFS 經典題,可能答案不是最優的,參考一下也是可以的 ^ _ ^

在這裏插入圖片描述

題目:

你玩過華容道的遊戲嗎?
這是個類似的,但更簡單的遊戲。
看下面 3 x 2 的格子

+---+---+---+
| A | * | * |
+---+---+---+
| B |   | * |
+---+---+---+

在其中放5張牌,其中A代表關羽,B代表張飛, * 代表士兵。
還有一個格子是空着的

你可以把一張牌移動到相鄰的空格中去(對角不算相鄰)。
遊戲的目標是:關羽張飛 交換位置其它的牌隨便在哪裏都可以

輸入格式:
輸入兩行6個字符表示當前的局面

輸出格式:
一個整數,表示最少多少步,才能把AB換位(其它牌位置隨意)

例如,輸入:

*   A
* * B

程序應該輸出:
17

再例如,輸入:

A B
* * *

程序應該輸出:
12


這個題目剛開始是使用 DFS做的,但是最後答案一直不對,隨後想了一下,發現 DFS是根本行不通的,因爲 DFS比較深度,將 A,B互換位置的次數不可能是最少的,大家可以畫個圖想一想 ^ _ ^

比如下面的代碼:
在這裏插入圖片描述
這是使用深搜思想(DFS)寫的,我們測試過的數據如下:
在這裏插入圖片描述
我們發現最少的情況也有 36步,但其實,這個地圖我們只需要 12步就可以完成 關羽 和 張飛的互換 . . .

而我們使用的最好解是使用 ——> BFS(廣度優先搜索)

BFS 是將當前最近的一個數據進行處理,大家可以動手畫一畫,爲什麼是使用 BFS是最好的 . . .

下面我將詳細的講解 BFS求解 《卡片換位》 . . .

.

BFS 思想求解

題目思想:

  1. 定位當前空格的所在位置,向四個方向一直探索
  2. 將空格與探索到的位置上的數據 互換
  3. 獲取更新後的地圖,並且與之前有過的地圖樣子相比,如若相同,則此路不行!進行下一個方向的探索
  4. 實時判斷是否已經將 關羽 和 張飛互換位置了 . . .

關鍵點解析:

  1. 首先,準備一個類,用於標識當前的狀態(空格位置、地圖樣子、空格移動步數):

    class Node
    {
    public:
        int currX;   	// 當前空格的所在位置
        int currY;
        string currStr; 	// 當前的字符串(地圖情景)
        int currStep;  	// 當前移動了多少步
    };
  2. 方向準備(上、下、左、右):

    // 下一個方向
    int nextDirection[4][2]{
        { 0, 1 }, 
        { 1, 0 }, 
        { 0, -1 }, 
        { -1, 0 } 
    };
  3. 準備一個隊列和集合容器(用於存放空格位置,判斷地圖是否重複):

    // 存放當前的一些數據(空格的位置、地圖、步數)
    queue<Node> que;       
    
    // 判斷當前的地圖是否在以前存在過了(避免循環移位)
    set<string> judgeIsNoRepetition;   
  4. 探索四個方向,並且判斷是否出界:

    for (size_t i = 0; i < 4; i++)
    { 
        // 獲取下一步的位置
        int cx = curr.currX + nextDirection[i][0];  
        int cy = curr.currY + nextDirection[i][1];
    }
  5. 地圖更新,並使用類封裝新的相關數據:

    // 空格到其它位置 產生的新的地圖
    string str = curr.currStr;   
    // 交換位置後,產生新的地圖
    swap(str[curr.currX * 3 + curr.currY], str[cx * 3 + cy]);
    
    Node tmp;  		// 當前最新生成的數據
    tmp.currX = cx;
    tmp.currY = cy;
    tmp.currStr = str;
    tmp.currStep = curr.currStep + 1;    // 上一步 + 1
  6. 判斷地圖是否存在過,避免重複:

    // 判斷這個地圖是否重複過 ! ! !
    if (judgeIsNoRepetition.count(tmp.currStr) != 0) continue;
    
    judgeIsNoRepetition.insert(tmp.currStr);  // 加入到集合這中
    que.push(tmp);         // 入隊,繼續進行下一步同樣的操作

重要的步驟就上面的這些,下面是完整的代碼,大家看懂之後,可以自己寫一遍,^ _ ^

在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

代碼和圖片的順序一樣

.

點個贊哈 !!!

浪子花夢

一個有趣的程序員 ~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章