用Dijkstra演算法解決狼羊菜渡河問題

2021-10-06 03:47:16 字數 4039 閱讀 4000

乙隻狼,乙隻羊和一筐白菜在河的一岸,乙個擺渡人想把它們都渡到河的另一岸去。但是由於他的船很小,每次只能帶走它們之中的一樣。由於明顯的原因,狼和羊或者羊和白菜在一起需要人看守。問擺渡人怎麼樣把它們渡過河?

用四維陣列(a,

b,c,

d)(a,b,c,d)

(a,b,c

,d)表示狼,羊,菜,擺渡人的位置狀態,其中a,b

,c,d

∈a,b,c,d \in \

a,b,c,

d∈,0

00表示還沒過岸,1

11表示已經到了河的另一邊。

1. 根據狼羊無法共存和羊菜不能共存,從24=

162^4=16

24=1

6種情況中篩選出可能存在的狀態,並視每乙個狀態為乙個頂點,得到頂點集vvv;

2. 根據擺渡人每次只能運輸1件物品(嚴格來講小於等於1件),推出所有可以直接相互轉化的狀態對(vi

,vj)

(v_i,v_j)

(vi​,v

j​),得到邊集eee;

3. 此時我們得到了乙個無向圖g=(

v,e)

g=(v,e)

g=(v,e

)(實際上也是乙個二部圖,頂點集可以分**在河原岸的集合x:=

x:=\

x:=和人在河對岸的集合y:=

y:=\

y:=,x,y

x,yx,

y中的任兩頂點不相鄰);

4. 原問題等價於求從點(0,

0,0,

0)(0,0,0,0)

(0,0,0

,0)到點(1,

1,1,

1)(1,1,1,1)

(1,1,1

,1)的最短路徑和相應的路徑長。

import networkx as nx

import matplotlib.pyplot as plt

# (a,b,c,d)表示狼羊菜人的位置狀態,其中a,b,c,d=0或者1,

# 0表示不在對岸,1表示在對岸

# 生成狼羊菜的所有可行的狀態

v =[

(a, b, c, d)

for a in

range(2

)for b in

range(2

)for c in

range(2

)for d in

range(2

)]for(a, b, c, d)

in v:

# 狼和羊,羊和白菜在一起時需要人看守

if(a == b and d != a)

or(b == c and d != b)

: v.remove(

(a, b, c, d)

)# 計算出所有可以相互之間轉化的狀態,即滿足條件:

# 1. 擺渡人有進行移動

# 2. 擺渡人每次運輸的東西不超過1件

g = nx.graph(

)edge_list =

for i in

range

(len

(v))

:for j in

range

(i +1,

len(v)):

if v[i][-

1]!= v[j][-

1]:# 擺渡人去了另一側

t =[item for

(index, item)

inenumerate

(v[i]

)if item == v[j]

[index]]if

len(t)

>=2:

# 帶了不超過1件東西過岸

(v[i]

, v[j],1

))# 生成無向圖並視覺化

g.add_weighted_edges_from(edge_list)

edge_labels =

dict([

((u, v)

, d[

'weight'])

for u, v, d in g.edges(data=

true)]

)pos = nx.spring_layout(g)

nx.draw_networkx_edge_labels(g, pos, edge_labels=edge_labels, font_size=15)

nx.draw_networkx(g, pos, node_size=

400)

plt.show(

)# 計算從初始狀態(0,0,0,0)到目標狀態(1,1,1,1)的最短路徑和相應的操作步數

print

('節點(0,0,0,0)到(1,1,1,1)的路徑:'

)path = nx.dijkstra_path(g, source=(0

,0,0

,0), target=(1

,1,1

,1))

print

(path)

print

('節點(0,0,0,0)到(1,1,1,1)的渡河次數: '

)distance = nx.dijkstra_path_length(g, source=(0

,0,0

,0), target=(1

,1,1

,1))

print

(distance)

# 列印出每一步具體的運輸詳情

for i in

range(1

,len

(path)):

text =

"第"+

str(i)

+"次渡河: "

if i%2!=

0:text +=

"原岸到對岸, "

else

: text +=

"對岸到原岸, "

if path[i][-

1]!=path[i-1]

[-1]

: text +=

"擺渡人+ "

if path[i][0

]!=path[i-1]

[0]:

text +=

"狼+ "

if path[i][1

]!=path[i-1]

[1]:

text +=

"羊+ "

if path[i][2

]!=path[i-1]

[2]:

text +=

"菜+ "

text = text[:-

2]print

(text)

無向圖視覺化效果:

計算結果:

節點(0,

0,0,

0)到(1,

1,1,

1)的路徑:[(

0,0,

0,0)

,(0,

1,0,

1),(

0,1,

0,0)

,(0,

1,1,

1),(

0,0,

1,0)

,(1,

0,1,

1),(

1,0,

1,0)

,(1,

1,1,

1)]節點(0,

0,0,

0)到(1,

1,1,

1)的渡河次數:

7第1次渡河: 原岸到對岸, 擺渡人+ 羊

第2次渡河: 對岸到原岸, 擺渡人

第3次渡河: 原岸到對岸, 擺渡人+ 菜

第4次渡河: 對岸到原岸, 擺渡人+ 羊

第5次渡河: 原岸到對岸, 擺渡人+ 狼

第6次渡河: 對岸到原岸, 擺渡人

第7次渡河: 原岸到對岸, 擺渡人+ 羊

C 演算法 狼羊菜過河問題

namespace 狼羊菜過河問題 物件陣列 static string start new string 開始情況 static string end new string 結束情況 static int cnt objects.length 幾種物件 static int count 0 解決方...

演算法謎題系列1 狼羊人問題

有乙個人,乙隻羊,乙隻狼,一捆菜 狼可以吃羊,羊可以吃菜,只有人在的情況,才避免吃的情況 準備過河。有一條船隻能載兩樣東西過河 人也算是一樣東西,只有人才會往返坐船,其它不會 如何過才會全部安全過河 沒有吃的現象 分析 可用自動機方法來解決,乙個狀態可形式化表示為,即people sheep wol...

練習程式 演算法系列14 狼 羊 菜和農夫過河問題

參考2 函式物件 關於仿函式 函式物件 ptr fun 參考3 bind2nd使用 include include include include using namespace std const int action count 8 一共有8種動作 int dfs deep 0 int resu...