傳教士與野人過河問題 人工智能實驗報告

實驗目的

  1. 理解並熟悉掌握深度優先搜索算法。
  2. 將所學人工智能理論知識綜合運用到具體項目當中。

問題描述

  有 N 個傳教士和 N 個野人來到河邊渡河,河岸有一條船,每次至多可供 k 人乘渡。問:傳教士爲了安全起見,應如何規劃擺渡方案,使得任什麼時候刻, 河兩岸以及船上的野人數目老是不超過傳教士的數目(不然不安全,傳教士有可能被野人吃掉)。 即求解傳教士和野人從左岸所有擺渡到右岸的過程當中,任什麼時候刻知足 M (傳教土數) ≥ C 野人數)和 M+C≤k 的擺渡方案。算法

算法分析

       假設以傳教士和野人的數量N爲3,船一次最大的載人量K爲2分析。數組

  初始狀態:河左岸有3個野人河3個傳教士;河右岸有0個野人和0個傳教士;船停在左岸,船上有0我的。安全

  目標狀態:河左岸有0個野人和0個傳教士;河右岸有3個野人和3個傳教士;船停在右岸,船上有0我的。多線程

  將整個問題抽象成怎樣從初始狀態經一系列的中間狀態從而達到目標狀態,狀態的改變是經過划船渡河來引起的。函數

根據要求,共得出如下5中可能的渡河方案:優化

  (1)渡2傳教士人工智能

  (2)渡2野人spa

  (3)渡1野人1傳教士線程

  (4)渡1傳教士code

  (5)渡1野人

  本程序使用類來定義狀態結點,使用集合存儲狀態結點,使用遞歸(深度優先查詢)的思想來尋找目標狀態。

實驗內容

程序執行流程

  首先,包含狀態(首次爲初始狀態)的結構體結點(已存入結構體數組)傳入處理函數,而後判斷該傳入結點狀態是否爲目標狀態。

  是則遍歷打印結構體數組,打印完成以後,返回遞歸調用處,順序執行以後代碼(此步驟關係到是否能找到全部過河路徑);

  不然繼續判斷是否該傳入結點已存在於結構體數組當中,如存在,再也不往下執行,返回遞歸調用處,順序執行以後代碼;

  若不存在,則繼續判斷該傳入狀態的人數是否合理(是否出現人物數量小於0的狀況等),若不合理,返回遞歸調用處,順序執行以後代碼;

  若合理,則繼續判斷傳教士和野人人數限制條件,即在傳教士人數不爲0的狀況下,野人人數是否大於傳教士人數,若大於則出現吃人的狀況,也就是說該傳入狀態也不合理,則返回遞歸調用處,順序執行以後代碼;

  若不知足大於條件,則說明該狀態是路徑轉態,也就是合理的,那麼進行五種渡河方案的依次變換,首先爲第一種渡河方案,兩個傳教士過河(注意:此處的5中渡河方案沒有固定順序,也能夠是其餘渡河方案),那麼對該傳入狀態的左岸和右岸的傳教士人數和野人人數進行增減(若爲左岸到右岸,則左岸人數減,右岸人數加,此處有一個小技巧見本段末尾)。

  增減完成並改變船的狀態(使用正負一表示,正一爲左岸,負一爲右岸)之後就產生了一個新的狀態,將該狀態存入結構體數組,以後此處又遞歸調用處理函數,將新產生的轉態結點傳入,再次進行上述條件限制判斷。

  若在該判斷途中被返回至遞歸調用處,說明該狀態不合理,則此時將已經存入結構體數組的狀態結點移出結構體數組,而後程序順序執行,進行下一個渡河方案的處理,也就是說,此時的處理是對上一個傳入結點的操做(由於剛傳入的已經移出了);

  若在判斷途中未被返回至遞歸調用處,也就是說,傳入的結點合理了,那麼又開始從第一種渡河方案開始對該傳入狀態進行操做。

  按照上述過程循環執行,直到出現目標狀態,回到本段開頭,遍歷結構體數組,打印渡河路徑結點信息。

  完成之後,返回遞歸調用處,順序執行以後代碼,此後的操做是在尋找其餘渡河路徑。

  原理爲:因爲該處理函數末尾存在return語句(關鍵),因此在找到目標狀態並返回以後,目標轉態結點一樣會被移出結構體數組,而後在其上一個結點開始順序往下執行操做以後的一種渡河方案,查看是否在該結點處,還有其餘渡河方案能夠達到目標狀態,如有則一樣按上述方法執行(打印輸出),若執行完後面的全部渡河方案,發現都沒有可以達到目標狀態的結點,則會執行末尾的返回語句,返回以後,該狀態結點也會被移除(關鍵),那麼此時操做的狀態結點就是上上個結點狀態,對其進行其後的渡河方案操做。按照此法,不斷日後退,直到全部結點都被移除,此時說明已經完成全部渡河路徑的搜索(深度)。至此,本程序的執行過程敘述完畢。

  小技巧:從左岸到右岸,和從右岸到左岸的狀態變化是不同的,前者左岸的人數減,右岸的人數加;後者左岸的人數加,右岸的人數減。咱們不該單獨再寫程序來處理,而是應該使用船的轉態帶入計算來處理,注意,此技巧在於船的轉態使用正負一來表示,而不該該是1和0,以及其餘表示方法。爲何這麼說?由於任何數乘以一,其自己都不會改變(有我也不會認可)。而正負號在此起到關鍵做用,咱們使用正負一去乘以五種渡河方案的改變數值,從而獲得的就是咱們變換的正確結果,不論左岸右岸,都是正確合理的。

原理推導

  上述原理徹底是按照傳教士和野人數量爲3人,船一次的載客量最大爲2爲前提所得。結合上述分析不難看出,當還沒有規定傳教士和野人具體數量以及船一次最大載客量爲多少時,與以前分析的差異僅僅在於根據人數不一樣,從河一端到另外一端一共有多少中 載客方式,其餘的原理流程與傳教士和野人數量爲3人,船一次的載客量最大爲2的流程所有相同。

關鍵代碼

主要用來判斷這條方案是否可行。

           // 是否重複操做
            for (int i = 0; i < index; i++)
            {
                if (m.left_c == m_fun[i].left_c && m.left_y == m_fun[i].left_y)
                {
                    if (m.boat_location == m_fun[i].boat_location)
                    {
                        return 0;
                    }
                }
            }
            // 人數是否合理
            if (m.left_c < 0 || m.left_y < 0 || m.right_c < 0 || m.right_y < 0)
            {
                return 0;
            }
            // 傳教士的人數是否大於等於野人
            if ((m.left_c < m.left_y && m.left_c != 0) || (m.right_c < m.right_y && m.right_c != 0))
            {
                return 0;
            } 

遞歸算法,主要是用來計算船的渡河載客可能性。

           // 遞歸算法
            for (int cchuan = chuan; cchuan >= 0; cchuan-- )
            {
                for (int ychuan = chuan; ychuan >= 0 ; ychuan--)
                {
                    if ((cchuan >= ychuan && cchuan + ychuan <= chuan && cchuan + ychuan>0) || (cchuan < ychuan && cchuan == 0))
                    {
                        mm.left_c = m.left_c - cchuan * m.boat_location;
                        mm.left_y = m.left_y - ychuan * m.boat_location;
                        mm.right_c = m.right_c + cchuan * m.boat_location;
                        mm.right_y = m.right_y + ychuan * m.boat_location;
                        mm.boat_location = (-m.boat_location);
                        index = index + 1;
                        m_fun.Insert(index, mm);
                        mCalculation(m_fun[index]);
                        index = index - 1;
                    }
                }
            }

實驗截圖

 

  運算結束會在「渡河方案」內顯示有多少套可行方案以及每一套方案的具體渡河步驟。

  左傳:河左岸傳教士人數\n左野:河左岸野人人數

  右傳:河右岸傳教士人數\n右野:河右岸野人人數

  船:船如今的位置(1::表示船在河的左岸;-1:表示船在河的右岸)

實驗缺陷

  此程序僅僅實現計算效過,尋找出全部可執行方案,並未開多線程進行優化。所以當計算數據過大時,界面進程堵塞,會形成程序中止響應,不過不用擔憂,程序依舊在後臺運算。當程序使用足夠時間運行完畢後,程序將會從新響應並展現全部的可行方案!計算須要必定的時間,計算過程當中請耐心等待。

實驗總結

  經過本次試驗,掌握學會了深度優先搜索算法。

  可以很好的將所學人工智能理論知識綜合運用到具體項目當中。

相關文章
相關標籤/搜索