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