365. 水壶问题
有两个容量分别为 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
解题思路一:
分析一下
不可能有两个壶同时处于不满不空的状态
装满只对空瓶操作,否则相当于之前操作作废
倒水不改变水的总量
装满操作是加法
清空操作是减法
二者都以操作对象容量为运算对象
操作次数相当于系数
运算结果为mx+ny
验证一下对系数基本没有要求,运算结果只要在允许范围内都可以得到
代码实现
mx+ny的取值是最大公因数的倍数
只要验证z是不是最大公因数的倍数就好了
代码如下:
class Solution {
public:
bool canMeasureWater(int x, int y, int z) {
if(z<0||z>x+y)
return false;
if(z==0) return true;//边界
int g;
if(x==0||y==0)//除数不为0
g=x+y;
else
g=gcd(x,y);
return z%g==0;
}
int gcd(int a,int b)//辗转相除法,找出最大公约数
{
if(a%b==0)
return b;
return gcd(b,a%b);
}
};
思路二:利用深度优先搜索
class Solution {
public:
bool canMeasureWater(int x, int y, int z) {
int a[2];
a[0]=x;a[1]=y;
bool ans=true;
dfs(a,x,y,z,ans);
return ans;
}
void dfs(int a[],int x,int y,int z,bool &ans){
if(sizeof(a)==2){
int a1=a[0],a2=a[1];
if(a1==z || a2==z || a1+a2==z){
ans=true;
return;
}
a[0]=0;
a[1]=a2;
dfs(a,x,y,z,ans);//将x倒完
a[0]=a1;
a[1]=0;
dfs(a,x,y,z,ans);//将y倒完
a[0]=x;
a[1]=a2;
dfs(a,x,y,z,ans);//将x灌满
a[0]=a1;
a[1]=y;
dfs(a,x,y,z,ans);//将y灌满
a[0]=max(a1-(y-a2),0);
a[1]=min(a2+a1,y);
dfs(a,x,y,z,ans);//从x向y倒
a[0]=min(a2+a1,x);
a[1]=max(a2-(x-a1),0);
dfs(a,x,y,z,ans);//从y向x倒
}
}
};//会陷入无限循环,需要改进目前无方案解决