選了李翠華老師的計算智慧型課程,第一次作業是解決乙個小孩分油問題,把實驗報告和**上傳,留底。
1.問題描述
編寫乙個程式,解決下列問題:
小孩分油問題:兩個小孩去打油,一人帶了乙個一斤的空瓶,另乙個帶了乙個七兩、乙個三兩的空瓶。原計畫各打一斤油,可是由於所帶的錢不夠,只好兩人合打了一斤油,在回家的路上,兩人想平分這一斤油,可是又沒有其它工具。試僅用三個瓶子(一斤、七兩、三兩)精確地分出兩個半斤油來。
2.演算法設計
資料結構:
vector<
int> b;
/*乙個vector中有三個數,分別表示一斤瓶、七兩瓶和三兩瓶的油量*/
bool vis[
10010];
/*記錄某狀態是否被遍歷過,乙個狀態用b[0]*100+b[1]*10+b[2]表示*/
int cap[3]
=;/*記錄每個瓶子的容量*/
queue
int>
> q;
/*bfs中使用的佇列*/
struct path
由題意分析這可以用搜尋做,一共有三個瓶子,每個瓶子可以向其他兩個瓶子倒油,或者保持自己當前的狀態,也就是每次輪到瓶子x,它有三條路可以走,所以這時用寬度優先搜尋(bfs),每次搜尋三個狀態,當目前狀態為(5,5,0)時退出,這時我們搜到的第一結果必定是最短路,也就是倒油次數最少的方法。這邊需要注意的是我們需要輸出倒油的順序,也就是需要記錄寬度優先搜尋的路徑。其a->b的狀態轉移過程可由下圖表示:
其中,a、b分別表示瓶子a、b中目前的油量,cap(b)表示瓶子b的容量,cap為capacity的縮寫。
由上圖1可知,雖然我們有三種瓶子,但只需要乙個函式transform(vector b, int f, int t)就能表示所有的轉移,f(from)表示倒出油的瓶子,t(to)表示倒入油的瓶子。
由於a->b後,b也可以向a轉移,為了避免出現死迴圈,這裡我使用了記憶化搜尋,對於每次倒油,維護乙個布林陣列vis,記錄這個狀態是否被遍歷過,若是遍歷過,下次經過時就直接跳過。當遇到狀態(5,5,0)時退出搜尋,並輸出路徑以及所用的步數。
3.程式流程
1、用初始化vector b;
2、呼叫bfs函式;
3、將b存入佇列q中,使用while迴圈判斷q是否為空,若為空則退出;
4、若不為空,則將q的第乙個節點取出,f++,f表示當前節點有多少個,記錄路徑用;
5、判斷當前節點是否為(5,5,0),若是則將記錄當前節點f,並回到main函式,否則轉到6;
6、使用for迴圈,分別對vector中的三個節點使用transform函式,若是transform函式出來的結果陣列是已經被遍歷過,則不處理,若沒遍歷過,就將這個狀態記錄到路徑中,並將該節點存入q中;
7、當回到main函式後,呼叫output函式來輸出路徑,由於我們找到的節點f是最後乙個節點,所以我們需要先回溯到第乙個節點,再輸出。遞迴output(path[f].pre)找到pre為0的點,然後再輸出就可以了。
4.核心偽**
vector<
int>
transform
(vector<
int> b,
int f,
int t)
else
return b;
}void
bfs(vector<
int> b)
q.pop();
for(
int i =
0;i <
3;i++
)else}}
}}return;}
void
output
(int i)
簡單測試:
寬度優先搜尋BFS
寬度優先搜尋 bfs,breadth first search 也是搜尋的手段之一。它與深度優先搜尋類似,從某個狀態出發探索所有可以到達的狀態。與深度優先搜尋的不同之處在於搜尋的順序,寬度優先搜尋總是先搜尋距離初始狀態近的狀態。也就是說,它是按照開始狀態 只需1次轉移就可以到達的所有狀態 只需2次轉...
寬度優先搜尋(BFS)
bfs,其英文全稱是breadth first search。0 1 4 2 3思路 從圖中某個節點出發,將該結點入隊,標記為已訪問。然後輸出佇列的隊首 第一次為起點 將隊首從佇列中刪除,訪問該結點的鄰接表,將未標記的相鄰結點入隊,並且標記為已訪問。接下來迴圈操作第二句話。按照上邊的圖,假設出發點為...
寬度優先搜尋bfs
好吧,今天看了bfs,其實發現基本思想也是不過如此。只是,應用還是不太會。bfs是寬度優先,從根節點開始,依次訪問它的所有鄰接點,然後再按順序訪問鄰接點的鄰接點,先被訪問的點的鄰接點先被訪問。由於要按這樣的順序訪問,所以需要用到佇列。求最短路徑和迷宮型別的題目都可以利用bfs.下面是基本步驟 1 從...