zoukankan      html  css  js  c++  java
  • LeetCode 365.水壶问题

    在这里插入图片描述

    有明确的初始状态和最终状态

    可以使用BFS来解决,主要考虑下一步可能状态next的求解,是个体力活

    import java.util.*;
    
    class Solution {
        private int x;
        private int y;
        private HashSet<String> status = new HashSet<>();
        public boolean canMeasureWater(int x, int y, int z) {
            this.x = x;
            this.y = y;
            if(z == 0) return true;
            Queue<String> que = new LinkedList<>();
            que.add(x + " " + y);
            while (!que.isEmpty()) {
                String poll = que.remove();
                for (String next : next(poll)) {
                    que.add(next);
                    int num1, num2;
                    String[] s = poll.split(" ");
                    num1 = Integer.parseInt(s[0]);
                    num2 = Integer.parseInt(s[1]);
                    if(num1 ==  z || num2 == z || (num1 + num2 == z)){
                        return true;
                    }
                }
    
            }
            return false;
        }
    
        private HashSet<String> next(String poll) {
            HashSet<String> nexts = new HashSet<>();
            int num1, num2;
            String[] s = poll.split(" ");
            num1 = Integer.parseInt(s[0]);
            num2 = Integer.parseInt(s[1]);
            //装满
            if (num1 < x && !status.contains(x + " " + num2)) {
                nexts.add(x + " " + num2);
                status.add(x + " " + num2);
            }
            if (num2 < y && !status.contains(num1 + " " + y)) {
                nexts.add(num1 + " " + y);
                status.add(num1 + " " + y);
            }
            //清空
            if (num1 > 0 && !status.contains(0 + " " + num2)) {
                status.add(x + " " + num2);
                nexts.add(x + " " + num2);
            }
            if (num2 > 0 && !status.contains(num1 + " " + 0)) {
                nexts.add(num1 + " " + 0);
                status.add(num1 + " " + 0);
            }
            //倒
            if (num1 > 0 && num2 < y) {
                int left = y - num2;
                if(num1 > left && !status.contains((num1 - left)+" "+ y)) {
                    nexts.add((num1 - left) + " " + y);
                    status.add((num1 - left) + " " + y);
                }
                if(num1 == left && !status.contains(0+" "+y)) {
                    nexts.add(0 + " " + y);
                    status.add(0 + " " + y);
                }
                if(num1 < left && !status.contains(0+" "+(num1+num2))) {
                    nexts.add(0 + " " + (num1 + num2));
                    status.add(0 + " " + (num1 + num2));
                }
            }
            if (num2 > 0 && num1 < x) {
                int left = x - num1;
                if(num2 > left && !status.contains(x+" "+ (num2 - left))) {
                    nexts.add(x + " " + (num2 - left));
                    status.add(x + " " + (num2 - left));
                }
                if(num2 == left && !status.contains(x+" "+0)) {
                    nexts.add(x + " " + 0);
                    status.add(x+" "+0);
                }
                if(num2 < left && !status.contains((num1+num2)+" "+0)) {
                    nexts.add((num1 + num2) + " " + 0);
                    status.add((num1+num2)+" "+0);
                }
            }
            return nexts;
        }
    }
    

    解法二:贝祖定理

    我们认为,每次操作只会让桶里的水总量增加 x,增加 y,减少 x,或者减少 y

    你可能认为这有问题:如果往一个不满的桶里放水,或者把它排空呢?那变化量不就不是 x 或者 y 了吗?接下来我们来解释这一点:

    首先要清楚,在题目所给的操作下,两个桶不可能同时有水且不满。因为观察所有题目中的操作,操作的结果都至少有一个桶是空的或者满的;

    其次,对一个不满的桶加水是没有意义的。因为如果另一个桶是空的,那么这个操作的结果等价于直接从初始状态给这个桶加满水;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态分别给两个桶加满;

    再次,把一个不满的桶里面的水倒掉是没有意义的。因为如果另一个桶是空的,那么这个操作的结果等价于回到初始状态;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态直接给另一个桶倒满。

    因此,我们可以认为每次操作只会给水的总量带来 x 或者 y 的变化量。因此我们的目标可以改写成:找到一对整数 a, b,使得

    ax+by=z
    

    而只要满足 z≤x+y,且这样的 a,b 存在,那么我们的目标就是可以达成的。这是因为:

    a≥0,b≥0,那么显然可以达成目标。

    a<0,那么可以进行以下操作:

    y 壶倒水;

    y 壶的水倒入 x 壶;

    如果 y 壶不为空,那么 x 壶肯定是满的,把 x 壶倒空,然后再把 y 壶的水倒入 x 壶。

    重复以上操作直至某一步时 x 壶进行了 a 次倒空操作,y 壶进行了 b 次倒水操作。

    b<0,方法同上,x y 互换。

    而贝祖定理告诉我们,ax+by=z 有解当且仅当 zx,y 的最大公约数的倍数。因此我们只需要找到 x, y 的最大公约数并判断 z 是否是它的倍数即可。

    class Solution {
        boolean canMeasureWater(int x, int y, int z) {
            if (x + y < z) return false;
            if (x == 0 || y == 0) return z == 0 || x + y == z;
            return z % gcd(x, y) == 0;
        }
    
        private int gcd(int x, int y) {
            if(y%x == 0)
                return x;
            return gcd(y%x,x);
        }
        
    }
    
  • 相关阅读:
    软件配置管理
    VS2008单元测试之NUnit集成与应用(转)
    说说委托,匿名委托,Lamda表达式
    六种方式实现hibernate查询
    AjaxControl验证占位问题
    UL+Li常用效果
    Linq 方法表
    让枚举成员显示出中文信息(转)
    Linq to SQL 插入和获取ID
    正则表达式收集
  • 原文地址:https://www.cnblogs.com/HoweZhan/p/12539825.html
Copyright © 2011-2022 走看看