有兩個容量分別為 x公升 和 y公升 的水壺以及無限多的水。請判斷能否通過使用這兩個水壺,從而可以得到恰好 z公升 的水?
如果可以,最後請用以上水壺中的一或兩個來盛放取得的 z公升 水。
你允許:
示例 1: (from the famous 「die hard」 example)
輸入: x = 3, y = 5, z = 4示例 2:輸出: true
輸入: x = 2, y = 6, z = 5思路:目標容量是通過當前兩個瓶子相互減,通過遞迴相減遍歷出所有可能組合的,沒去探尋規律,因此稱為暴力法,不過其搜尋的方式也可以稱為深度優先搜尋。如果遞迴找到返回true,如果遍歷所有可能後沒找到,則返回false輸出: false
如果目標大於兩個瓶子容量和或目標為0,特殊處理
如果目標大於兩個瓶子容量,則減去大容量作為新目標容量,即原目標容量是新目標容量加上大容量
遞迴裡面不斷通過x和y對當前差值進行處理
遞迴的寫法,在測試用例數值比較大的時候會超出遞迴深度,因此最前面兩行是修改了python預設的遞迴深度。(如果不修改深度,超出深度的測試用例為:104597,104623,123)。
# author: [email protected]
import sys
sys.setrecursionlimit(
1000000
)class
solution
:def
dein
(self,s,x,y,z,t)
:if z == t:
# 找到
return
true
if s.__contains__(t)
:# 已經出現過,則不再遞迴
return
false
s.add(t)
return self.dein(s,x,y,z,
abs(x-t)
)or self.dein(s,x,y,z,
abs(y-t)
)def
canmeasurewater
(self, x:
int, y:
int, z:
int)
->
bool
:if z > x + y:
return
false
if z in(0
,x,y)
:#簡單特例
return
true
if z >
max(x,y)
: z = z -
max(x,y)
s =set(
)return self.dein(s,x,y,z,
max(x,y)
-min
(x,y)
)
思路:由於每次倒水操作都是全部倒掉或者倒滿,都可以看做是對x,y的整數次組合操作,即使用乙個二元一次方程進行求解判斷,將題目抽象為數學問題,可以理解為:
已知x,y,z三個正整數
判斷是否存在兩個整數a,b,使得線性方程可以滿足:ax+
by=z
ax + by = z
ax+by=
z,即在以ab為變數構成的二維座標系中,直線方程是否經過整數座標
a,b的約束條件為:不能同時大於等於1(同時等於1除外),即要檢查的座標點不考慮第一象限中(1,b)(a,1)的那一部分
在數論中有個貝祖定理,是這麼說的:
若x,y是整數,且x和y的最大公約數為k,一定存在整數a和b,使得ax+
by=k
ax+by=k
ax+by=
k成立進一步,等式ax+
by=z
ax+by=z
ax+by=
z有解的充要條件是:z是k的整數倍
另外,等式有解時必然有無窮多個整數解
從貝祖定理知道,本題目可以轉換為判斷,z是否能夠整除x和y的最大公約數。
ab的約束條件首先剔除(思路中的第3點)
輾轉相除得到最大公約數
判斷是否能整除最大公約數
class
solution
:# author: [email protected]
defcanmeasurewater
(self, x:
int, y:
int, z:
int)
->
bool
:if z > x + y:
#剔除約束條件
return
false
if z in(0
,x,y)
:#簡單特例
return
true
x, y =
max(x,y)
,min
(x,y)
while y >0:
#輾轉相除 得到 最大公約數
y, x = x % y, y
return z % x ==
0
思路:每次把每種可能的操作都執行一遍,如果滿足條件則返回true,否則每次把操作結果存入棧,每次取棧頂元素後持續查詢,直到將每次操作的可能性都遍歷完,本演算法使用棧來達到深度優先搜尋演算法,也可以使用佇列來達到廣度優先搜尋演算法。
每次操作最多有以下6種操作方式:
把x倒滿
把y倒滿
把x倒空
把y倒空
把x倒入y,可能把x倒空,也可能把y倒滿
把y倒入x,可能把y倒空,也可能把x倒滿
為了減少重複遍歷,引入visited集合進行過濾來判斷,這種方式跟解法一類似,也可以理解成暴力法,即基於具體規則的暴力破解。本解法使用迴圈來代替遞迴,用於避免超出python的預設最大遞迴深度,當然也可以類似解法一使用遞迴的方式實現。
class
solution
:# author: [email protected]
defcanmeasurewater
(self, x:
int, y:
int, z:
int)
->
bool
: stack =[(
0,0)
] visited =
set(
)while stack:
cx,cy = stack.pop(
)if z in
(cx,cy,cx+cy)
:return
true
if(cx,cy)
in visited:
continue
visited.add(
(cx,cy)
)#加入標籤減少重複遍歷
(x,cy)
)#1. 把x倒滿
(cx,y)
)#2. 把y倒滿(0
,cy)
)#3. 把x倒空
(cx,0)
)#4. 把y倒空
(cx-
min(cx,y-cy)
,cy+
min(y-cy,cx)))
#5. 把x倒入y,可能把x倒空,也可能把y倒滿
(cx+
min(x-cx,cy)
,cy-
min(cy,x-cx)))
#6. 把y倒入x,可能把y倒空,也可能把x倒滿
return
false
八皇后問題的兩種解法
八皇后問題,是回溯演算法 的典型案例。該問題是國際西洋棋棋手馬克斯 貝瑟爾於1848年提出 在8x8格的西洋棋 上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。高斯認為有76種方案。1854年在柏林 的象棋雜誌上不同的作者發表了40種不同的解,後...
6 2分魚問題兩種解法
分魚問題,從e開始遞推,使用for迴圈簡化中間計算,優化列舉 include using namespace std int main if i 0 已找到答案 break num 0 num 1 4 5 1 for int i 0 i 5 i cout num i return 0 分魚問題,從e...
約瑟夫環問題的兩種解法(詳解)
題目 josephus有過的故事 39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也不要被敵人抓。於是決定了自殺方式,41個人排成乙個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺。然後下乙個重新報數,直到所有人都自殺身亡為止。然而josephus 和他的朋友並...