You are given two jugs with capacities x and y litres. There is an infinite amount of water supply available. You need to determine whether it is possible to measure exactly z litres using these two jugs.
If z liters of water is measurable, you must have z liters of water contained within one or both buckets by the end.
Operations allowed:
- Fill any of the jugs completely with water.
- Empty any of the jugs.
- Pour water from one jug into another till the other jug is completely full or the first jug itself is empty.
Example 1: (From the famous "Die Hard" example)
Input: x = 3, y = 5, z = 4
Output: True
Example 2:
Input: x = 2, y = 6, z = 5
Output: False
题目链接:https://leetcode-cn.com/problems/water-and-jug-problem/
思路
法一:dfs递归
对于本题来说,这种方法非常耗时。但如果题目要求给出倒水步骤的具体解,数学方法就不行,需要用递归的方法。
!以下代码中关于set存储pair的内容是用的别人代码,目前只能照着背。
class Solution {
// 0-x装满,1-y装满,2-x倒光,3-y倒光,4-x全给y,5-y给x满上
public:
bool canMeasureWater(int x, int y, int z) {
if(z==0||z==x||z==y||z==x+y) return true;
if(z>x+y || z<0) return false;
if(x==0) return z==y;
if(y==0) return z==x;
auto hash_function = [](const pair<int,int>& o) {return hash<int>()(o.first) ^ hash<int>()(o.second);};
unordered_set<pair<int,int>, decltype(hash_function)> dp(0, hash_function);
stack<pair<int,int>> stk;
pair<int, int> cur = make_pair(0,0);
stk.push(cur);
while(!stk.empty()){
cur = stk.top();
stk.pop();
if(dp.count(cur)) continue;
dp.insert(cur);
int num1 = cur.first, num2 = cur.second;
if(x+num2==z || num1+y==z ||num1==z ||num2==z ||num1+num2==z) return true;
stk.emplace(x,num2);
stk.emplace(num1,y);
stk.emplace(0,num2);
stk.emplace(num1,0);
int num4y = min(y,num2+num1), num4x = max(num1+num2-y,0);
stk.emplace(num4x,num4y);
int num5x = min(x, num1+num2), num5y = max(0,num2-x+num1);
stk.emplace(num5x,num5y);
}
return false;
}
};
法二:数学规律
贝祖定理,z=ax+by 有解当且仅当 z 是 x,y 的最大公约数的倍数。因此我们只需要找到 x,y 的最大公约数并判断 z是否是它的倍数即可。
最大公因数可由辗转相除法计算得到。
class Solution {
public:
bool canMeasureWater(int x, int y, int z) {
if(z==0||z==x||z==y||z==x+y) return true;
if(z>x+y || z<0) return false;
if(x==0) return z==y;
if(y==0) return z==x;
int g = gcd(x,y);
return z%g==0;
}
int gcd(int a, int b){
if(a%b==0) return b;
else return gcd(b,a%b);
}
};