程式設計思維與實踐 Week2 作業2道

2021-10-03 12:45:44 字數 4820 閱讀 1529

這周作業主要是對廣度優先搜尋bfs的應用,包括求最短路徑的迷宮問題及隱式圖問題:倒水問題。

東東有一張地圖,想通過地圖找到妹紙。地圖顯示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹紙,這兩個位置保證為0。既然已經知道了地圖,那麼東東找到妹紙就不難了,請你編乙個程式,寫出東東找到妹紙的最短路線。

input

輸入是乙個5 × 5的二維陣列,僅由0、1兩數字組成,表示法陣地圖。

output

輸出若干行,表示從左上角到右下角的最短路徑依次經過的座標,格式如樣例所示。資料保證有唯一解。

sample input

0 1 0 0 0

0 1 0 1 0

0 1 0 1 0

0 0 0 1 0

0 1 0 1 0

sample output

(0, 0)

(1, 0)

(2, 0)

(3, 0)

(3, 1)

(3, 2)

(2, 2)

(1, 2)

(0, 2)

(0, 3)

(0, 4)

(1, 4)

(2, 4)

(3, 4)

(4, 4)

hint

座標(x, y)表示第x行第y列,行、列的編號從0開始,且以左上角為原點。另外注意,輸出中分隔座標的逗號後面應當有乙個空格。

之前資料結構課程學習到的迷宮老鼠問題可以用dfs,用先進後出的棧資料結構來求得一條路徑,但不一定是最短路徑。最短路徑則要用到bfs,一般在程式中需要用到先進先出的佇列資料結構。

可能距離上學期也過去了一段時間,對dfs和bfs不太熟悉了,在此來讓我們先回顧下相關知識。

深度優先搜尋

寬度優先搜尋

寬度優先搜尋(bfs,breadth-first search)也是搜尋的手段之一。它與深度優先搜尋類似,從某個狀態出發探索所有可以到達的狀態。與深度優先搜尋的不同之處在於搜尋的順序,寬度優先搜尋總是先搜尋距離初始狀態近的狀態。也就是說, 它是按照開始狀態→只需1次轉移就可以到達的所有狀態→只需2次轉移就可以到達的所有狀態→……這樣的順序進行搜尋。對於同乙個狀態,寬度優先搜尋只經過一次,因此複雜度為o(狀態數×轉移的方式)。

寬度優先搜尋按照距開始狀態由近及遠的順序進行搜尋, 因此可以很容易地用來求最短路徑、 最少操作之類問題的答案。

寬度優先搜尋時首先將初始狀態新增到佇列裡, 此後從佇列的最前端不斷取出狀態, 把從該狀態可以轉移到的狀態中尚未訪問過的部分加入佇列,如此往復,直至佇列被取空或找到了問題的解。通過觀察這個佇列,我們可以就知道所有的狀態都是按照距初始狀態由近及遠的順序被遍歷的。

深度優先搜尋與寬度優先搜尋的比較

深度優先搜尋(隱式地)利用了棧進行計算,而寬度優先搜尋則利用了佇列。

寬度優先搜尋與深度優先搜尋一樣, 都會生成所有能夠遍歷到的狀態, 因此需要對所有狀態進行處理時使用寬度優先搜尋也是可以的。 但是遞迴函式可以很簡短地編寫, 而且狀態的管理也更簡單,所以大多數情況下還是用深度優先搜尋實現。反之,在求取最短路時深度優先搜尋需要反覆經過同樣的狀態,所以此時還是使用寬度優先搜尋為好。

寬度優先搜尋會把狀態逐個加入佇列,因此通常需要與狀態數成正比的記憶體空間。反之,深度優先搜尋是與最大的遞迴深度成正比的。一般與狀態數相比,遞迴的深度並不會太大,所以可以認為深度優先搜尋更加節省記憶體

——摘自《挑戰程式設計競賽(第2版)》

其圖示詳細過程可參考:基本演算法——深度優先搜尋(dfs)和廣度優先搜尋(bfs) 分析

其中關鍵操作有:因為要向4個不同方向移動,用dx[4]和dy[4]兩個陣列來表示四個方向向量。這樣通過乙個迴圈就可以實現四方向移動的遍歷。同理,八個方向也可用類似陣列。

#include

#include

using

namespace std;

class

position;}

;class

path

:public position};

const

int size_of =7;

int maze[size_of]

[size_of]

;queue> path;

path *s =

newpath(1

,1,null),

*end_ =

newpath(5

,5,null);

const

int dx=

;//x的四個方向,八個方向同樣可以模擬

const

int dy=

;//y的四個方向

void

bfs(

int x,

int y)

for(

int i =

0; i <

4; i++)}

}}void

print

(path *p)

//遞迴順序輸出

else

}int

main()

else

cin >> maze[i]

[j];}}

bfs(1,

1);print

(end_)

;//從最後乙個開始找前乙個點直到起點

system

("pause");

return0;

}

倒水問題 「fill a」 表示倒滿a杯,"empty a"表示倒空a杯,「pour a b」 表示把a的水倒到b杯並且把b杯倒滿或a倒空。

input

輸入包含多組資料。每組資料輸入 a, b, c 資料範圍 0 < a <= b 、c <= b <=1000 、a和b互質。

output

你的程式的輸出將由一系列的指令組成。這些輸出行將導致任何乙個罐子正好包含c單位的水。每組資料的最後一行輸出應該是「success」。輸出行從第1列開始,不應該有空行或任何尾隨空格。

sample input

2 7 5

2 7 4

sample output

fill b

pour b a

success

fill a

pour a b

fill a

pour a b

success

notes

如果你的輸出與sample output不同,那沒關係。對於某個"a b c"本題的答案是多解的,不能通過標準的文字對比來判定你程式的正確與否。 所以本題由 spj(special judge)程式來判定你寫的**是否正確。

此題是乙個隱式圖問題,那麼什麼是隱式圖呢?

隱式圖是僅給出初始結點、目標結點以及生成子結點的約束條件(題意隱含給出),要求按擴充套件規則應用於擴充套件結點的過程,找出其他結點,使得隱式圖的足夠大的一部分程式設計顯式,直到包含目標結點為止。

一種很典型的隱式圖問題便是倒水問題。

可以轉移到不同的狀態。

對於每一種狀態,我們需要記錄是否已經被訪問過了(bfs的過程)

可以直接使用高維陣列記錄(本題),有時需要用 map/set 或雜湊算

法來記錄狀態

#include

#include

#include

#include

using

namespace std;

int a, b, c;

struct status

status

(int x1,

int y1,

int sta1)

bool

operator

<

(const status &b)

const

//不同種狀態

status atob()

status btoa()

status filla()

status fillb()

status emptya()

status emptyb()

};mapbool

> visited;

map from;

queue q;

void

check

(status x, status y)

}void

judge

(int i)

}void

print

(status t)

else

}void

bfs(

int a,

int b)

check

(t.atob()

, t)

;check

(t.btoa()

, t)

;check

(t.filla()

, t)

;check

(t.fillb()

, t)

;check

(t.emptya()

, t)

;check

(t.emptyb()

, t);}

}int

main()

return0;

}

程式設計思維與實踐 Week2 作業

b題 倒水問題 bfs 東東有一張地圖,想通過地圖找到妹紙。地圖顯示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹紙,這兩個位置保證為0。既然已經知道了地圖,那麼東東找到妹紙就不難了,請你編乙個程式,寫出東東找到妹紙的最短路線。input 輸入是乙個5 5的二維陣列,僅由0 1兩數字組成,...

程式設計思維與實踐 Week2 作業

b pour water 東東有一張地圖,想通過地圖找到妹紙。地圖顯示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹紙,這兩個位置保證為0。既然已經知道了地圖,那麼東東找到妹紙就不難了,請你編乙個程式,寫出東東找到妹紙的最短路線。輸入 輸入是乙個5 5的二維陣列,僅由0 1兩數字組成,表示...

程式設計思維Week2 作業

輸入乙個5x5的二維陣列由0 1組成,表示法陣地圖。地圖顯示,0表示可以走,1表示不可以走,左上角是起點,右下角是終點,這兩個位置保證為0。編寫程式,找到起點到終點的最短路線。要求輸出若干行,表示從左上角到右下角的最短路徑依次經過的座標。資料保證有唯一解。該題是典型的bfs演算法應用。由於題目要求輸...