• 365:水壶问题(C++)


    题目地址:https://leetcode-cn.com/problems/water-and-jug-problem/

    题目描述

    两个容量分别为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

    解题思路

    数学法:根据裴蜀定理可知,我们可以将问题转化为求解整数a和b使得等式ax+by = z,而满足等式的前提条件x+y>=z。由裴蜀定理得,ax+by=z有解当且仅当zx,y的最大公约数d的倍数。因此我们只需要找到x, y的最大公约数d并判断z是否是它的倍数即可。

    DFS法:根据牛客官网解析,深度优先搜索中的每一步以 remain_x, remain_y 作为状态,即表示 X 壶和 Y 壶中的水量。在每一步搜索时,我们会依次尝试所有的操作,递归地搜索下去。这可能会导致我们陷入无止境的递归,因此我们还需要使用一个哈希结合(HashSet)存储所有已经搜索过的 remain_x, remain_y 状态,保证每个状态至多只被搜索一次。

    在任意一个时刻,我们可以且仅可以采取以下几种操作:

    • 把 X 壶的水灌进 Y 壶,直至灌满或倒空;
    • 把 Y 壶的水灌进 X 壶,直至灌满或倒空;
    • 把 X 壶灌满;
    • 把 Y 壶灌满;
    • 把 X 壶倒空;
    • 把 Y 壶倒空。

    程序源码

    DFS法

    using PII = pair<int, int>;
    
    class Solution {
    public:
        bool canMeasureWater(int x, int y, int z) {
            stack<PII> stk;
            stk.emplace(0, 0);
            auto hash_func = [](const PII& o) {return hash<int>()(o.first) ^ hash<int>()(o.second);};
            unordered_set<PII, decltype(hash_func)> seen(0, hash_func);
            while (!stk.empty()) {
                if (seen.count(stk.top())) {
                    stk.pop();
                    continue;
                }
                seen.emplace(stk.top());
                
                auto [remain_x, remain_y] = stk.top();
                stk.pop();
                if (remain_x == z || remain_y == z || remain_x + remain_y == z) {
                    return true;
                }
                // 把 X 壶灌满。
                stk.emplace(x, remain_y);
                // 把 Y 壶灌满。
                stk.emplace(remain_x, y);
                // 把 X 壶倒空。
                stk.emplace(0, remain_y);
                // 把 Y 壶倒空。
                stk.emplace(remain_x, 0);
                // 把 X 壶的水灌进 Y 壶,直至灌满或倒空。
                stk.emplace(remain_x - min(remain_x, y - remain_y), remain_y + min(remain_x, y - remain_y));
                // 把 Y 壶的水灌进 X 壶,直至灌满或倒空。
                stk.emplace(remain_x + min(remain_y, x - remain_x), remain_y - min(remain_y, x - remain_x));
            }
            return false;
        }
    };

    数学法

    class Solution {
    public:
        bool 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;
        }
    };
    ----------------------------------- 心之所向,素履所往;生如逆旅,一苇以航。 ------------------------------------------
  • 相关阅读:
    AD 快捷键
    AD PCB 错误检查
    AD 在 PCB导出封装库
    AD PCB 机械层 画板步骤
    不同频率对PCB材料的要求
    RF 天线长度,通信距离估算
    RF硬件检查注意事项
    影响RSSI的因素
    阅读与思考
    面向对象特性分析
  • 原文地址:https://www.cnblogs.com/wzw0625/p/12536412.html
Copyright © 2020-2023  润新知