欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

LC365-水壶问题,使用裴枢定理和图表

最编程 2024-07-18 22:16:26
...

以下是看了官方题解之后,根据自己的理解画出的示意图,若有理解错误还请大家指出。若没有理解错误,希望大家能通过此示意图理解裴蜀定理的解法。

题目

有两个容量分别为 x升 和 y升 的水壶以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水?

如果可以,最后请用以上水壶中的一或两个来盛放取得的 z升 水。

你允许:

  • 装满任意一个水壶
  • 清空任意一个水壶
  • 从一个水壶向另外一个水壶倒水,直到装满或者倒空 示例 1: (From the famous "Die Hard" example)
输入: x = 3, y = 5, z = 4
输出: True
示例 2:
输入: x = 2, y = 6, z = 5
输出: False

问题

1、裴蜀定理的概念 2、对题目要求的理解 3、如何由此题联想到到裴蜀定理

解决

1、裴蜀定理,简单来说就是:

若x,y是整数,且gcd(x,y)=d,那么对于任意的整数a,b,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。

2、根据题目要求我们可以知道我们可以有如下操作:

  • 装满任意一个水壶:从外界装满
  • 清空任意一个水壶:向外界倒出
  • 从一个水壶向另外一个水壶倒水,直到装满或者倒空: 所以可知每次操作之后总会有一个桶是满的或者空的,另外一个是空还是满还是非空都可以。

3、由2可知,每次的水的总量总是变化x或者y:这个变化可以理解为 (1)向外界倒出 (2)从外界倒入 注意:这里说的水的总量是两个桶内水的总量的变化总是x或者y。两个桶之间水的转移不算一次变化,因为水的总量没有变化,你只是换了个地方存水而已

那么我们只要找到x和y分别变化了几次能得到z就行了,即ax+by=z

其中a和b代表水的总量变化了a次或者b次,为负代表向外界倒了,为正代表从外界倒入,至于两个桶之间水的转移是不管的,因为无非就是从这个桶倒入另一个桶而已,两个桶内的总量没有变化。

根据这个等式可以想到裴蜀定理。为什么说可以想到呢?前提当然是你要知道这个定理的内容,就如同你要钉一个钉子,知道有锤子这个工具的存在,锤子很坚硬就适合钉钉子(比喻可能不太恰当)。裴蜀定理跟这个公式长得几乎一模一样,而且裴蜀定理求得的值都是x和y的最大公约数的倍数,那么题目给出了x和y,容易得到最大公约数,只要验证z是不是其倍数就能得出答案,至于a和b是几我们并不关心,因为根据裴蜀定理一定存在。

举个例子来实际感受一下

假设: x=3, y=5, z=4 根据裴蜀定理可知 (-2)*3 + 2*5 = 4a=-2, b=2 代表:向外界倒出了2次3L的水,从外界向桶内倒入了2次5L的水,然后就得到了4L的水 如图:一定要注意,我们讨论的基本单位是水的总量变化。 因为不会加自己切换的图片样式,只能加入gif了????

水壶问题.gif

若还是不理解为什么讨论的水的总量变化,可以这样理解:上图的最后一步,两个桶剩下0L和4L的水,如果多此一举把4L的水倒入3L桶中,造成两个桶是3L和1L这样的状态,这样是没有意义的==因为水还是4L,水的总量没有变化,所以你爱咋放咋放,只要能够装下就行。所以我们讨论的水的总量的变化

//裴蜀定理
class Solution 
{
public:
    bool canMeasureWater(int x, int y, int z) 
    {
        if (x + y < z) return false;
        if (x == 0 || y == 0)
        {
            if (z == 0) return true;
            if (x + y == z) return true;
            return false;
        }
        return z % gcd(x, y) == 0;
    }
};

参考

LC官方题解