每日一题.每日一练 .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

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