每日一題.每日一練 .6.水壺問題(寫完感覺自己能去講課版)

有兩個容量分別爲 x升 和 y升 的水壺以及無限多的水。請判斷能否通過使用這兩個水壺,從而可以得到恰好 z升 的水?

如果可以,最後請用以上水壺中的一或兩個來盛放取得的 z升 水。

你允許:

裝滿任意一個水壺 清空任意一個水壺 從一個水壺向另外一個水壺倒水,直到裝滿或者倒空 (From the famous “Die
Hard” example)

示例 1:
輸入: x = 3, y = 5, z = 4
輸出:
True

示例 2:
輸入: x = 2, y = 6, z = 5
輸出:
False

這不是五分鐘能解決的了==,花了一小時看貝祖定理沒看明白,數學好菜
首先先給一個貝祖定理的結論
當存在ax+by=z時,當且僅當x,y的最大公約數是z的倍數時有解(看了一小時也沒看明白貝祖定理的證明==)

對於水壺問題我們可以這樣認爲,每次操作過後,水壺的總量的水只是增加x,減少x或者增加y ,減少y,如果你把部分水倒掉或將部分水填滿,比如x桶 2升,y桶0升,如果我們對x桶進行操作,有兩種可能:
倒滿,那麼就和把一個空的x桶倒滿是一樣的結果
倒空,那麼就和最開始的x什麼都不動是一樣的結果

這裏可能有點繞,我們嘗試簡述一下。

我們先引入兩個變量y_now和x_now,這兩個變量代表某一時刻x,y兩瓶裏剩餘的水量。

首先我們的目的是獲得x_now+y_now=z(x_now和y_now都可以爲0),也就是說我們在某一時刻發現兩瓶水的總量是z,那麼問題就解決了。而總量出現部分水(即當前總量並不是x,y,x+y,零,下文同)的情況滿足以下幾個條件

1:當出現了部分水的情況時,至少有一個瓶子存在着不滿不空的狀態(全滿,全空,一滿一空都不符合部分水的前提)

2:不發生任何瓶子轉移的情況,不會出現部分水(永遠不往另一個瓶子裏倒,只有滿或者空)

3:兩個瓶子不會同時出現不滿不空的情況,因爲如果你在轉移後手裏的這個瓶子在還有水,只可能是你在倒的另一個瓶子裝不下了(你不能倒一半,除非你是被迫的),否則你手裏的這個瓶子只能裝滿(接水)或是一個空瓶(倒光)

因此,如果z不是部分水,我們不用發生瓶子轉移就能得到,而如果z是部分水,我們就需要讓一個瓶子不滿不空(即總量可能是部分水從而得到z的情況),而一個瓶子在發生瓶子轉移後存在不滿不空的情況只有兩種

第一種是你手上拿着的水沒有辦法全扔到另一個瓶子裏面去,這個時候出現了手上的這個瓶子不滿不空的情況,它的水量是(x_now-(y-y_now))或者是y_now-(x-x_now)),取決於你手上的瓶子是哪個(當然你手上的瓶子也可能有剩水也可能接滿了)以及另一個瓶子還能裝多少(當然另一個瓶子剩餘的水可能是零,就是往空瓶轉移),這時候你手上的這個瓶子變爲不滿不空

比如手上拿着2升裝滿水的瓶子往7升已經有6升水的瓶子倒
那麼那個不滿不空的瓶子就是2-(7-6)=1

再比如手上拿着6升裝了4升水的瓶子往2升空瓶倒
那麼那個不滿不空的瓶子變成了4-(2-0)=2

第二種是你把水倒進去另一個瓶子裏發現沒有裝滿,那麼被倒入的那個瓶子出現了不滿不空的情況,很好理解,那麼這個不滿不空的瓶子水量是(x_now+y)或者是(y_now+x),(這裏如果倒入了空瓶,並不是部分水的情況,因爲總量不符合我們當初的定義,所以部分水一定存在不滿不空的瓶子,但不滿不空的瓶子不一定是部分水
比如兩個空瓶3往7倒,總量還是3

那麼接下來是關鍵點

第一個不滿不空的瓶子是怎麼出現的?
也許我們在第i個操作變出了一個不空不滿的瓶子,從而使得水的總量跳出了x和y的限制,但是我們研究一下,由於一個瓶子不空不滿只有上述的兩種情況因此,這個不滿不空的瓶子所有的水量可以通過上一個時刻變化後剩下來的水的狀態來求,一開始剩下的水有哪幾種可能?,沒錯就是x,y,0,換句話說,在發生瓶子轉移出現了第一個不空不滿的瓶子時,這個不空不滿的瓶子一定能用x和y來表達
從而我們可以利用這兩個條件來遞推

1,.任意i時刻的那個不滿不空的瓶子剩餘的水量,我們都可以由i-1時刻的兩瓶中剩餘的水量推出,且其中至少有一個瓶子非滿即空(因爲只有一個瓶子存在不滿不空)
2,當第n時刻第一次一個瓶子存在不滿不空的狀態時,這個瓶子的剩餘水量可以由x,y表達

也就是說,既然x,y能表達第一次出現的剩餘水量,那麼就可以遞推表達之後某個時刻的剩餘水量,而因爲只有一個瓶子存在不滿不空的情況,所以另一個瓶子只有三種可能,x,y,或者0,因此我們可以得到如下推斷
(這裏假設x是不滿不空的瓶子)

部分水=不滿不空的瓶子+另一個瓶子
(部分水=now_x+now_y)
任意時刻不滿不空的瓶子可以用x和y線性表達
(ax+by=now_x)(每轉移一次是x和y的加減變化)
另一個瓶子存在x,y,0三種情況
(now_y=x or y or 0)

因此得到結論,若存在任意時刻i,使得ax+by=z(a和b爲任意整數,因此另一個瓶子的影響被忽略掉了。)則我們可以說題目有解,可以得到z,

於是我們引入貝組定理,求最大公約數,代碼如下

class Solution:
    def canMeasureWater(self, x: int, y: int, z: int) -> bool:
        ch=0
        if(z==0):
            return True
        if(x+y<z or x*y==0):
            return False
        if(x<y):
            ch=x
            x=y
            y=ch
        mid=y
        while(x%y):
            mid=x%y
            x=max(mid,y)
            y=min(mid,y)
        if(z%mid==0):
            return True
        else:
            return False

學到了不少,兩小時沒了QWQ

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章