有两个容量分别为 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
【来源】
思路
可以dfs或bfs,不过因为操作步数确定,bfs显然更好
对于桶中水量,有6种可能的操作,用pair<int,int>保存状态,用哈希set记录访问的状态,然后直接bfs即可
- 把x桶装满
- 把y桶装满
- 把x桶倒空
- 把y桶倒空
- 把x桶的水倒入y直到x空或y满
- 把y桶的水倒入x直到y空或x满
借助队列实现bfs不难,关键是如何对重复的(x, y)二元组标识访问?
定义哈希set,存储的元素是pair<int,int>
这就要求对pair<int,int>
实现哈希函数,(pair的比较函数已经自带了)
【关于如何改写哈希】
代码
这里使用的是层次遍历模板的bfs,方便求出操作次数
class Solution {
public:
bool canMeasureWater(int x, int y, int z)
{
if(z==0 || z==x+y) return true;
if(z>x+y) return false;
struct hashfunc
{
size_t operator() (const pair<int,int> p) const
{
return size_t(p.first)*1000000007+p.second;
}
};
unordered_set<pair<int,int>, hashfunc> hash;
deque<pair<int,int>> q;
q.push_back(pair<int,int>(0, 0)); hash.insert(pair<int,int>(0,0));
while(!q.empty())
{
int qs = q.size();
for(int i=0; i<qs; i++)
{
pair<int,int> tp=q.front(), next; q.pop_front();
int X=tp.first, Y=tp.second;
if(X+Y==z) return true;
next = pair<int,int>(x, Y);
if(hash.find(next)==hash.end())
hash.insert(next), q.push_back(next);
next = pair<int,int>(X, y);
if(hash.find(next)==hash.end())
hash.insert(next), q.push_back(next);
next = pair<int,int>(0, Y);
if(hash.find(next)==hash.end())
hash.insert(next), q.push_back(next);
next = pair<int,int>(X, 0);
if(hash.find(next)==hash.end())
hash.insert(next), q.push_back(next);
int x_=(X+Y>=x)?(x):(X+Y), ry=(X+Y>=x)?(x-X):(0);
int y_=(X+Y>=y)?(y):(X+Y), rx=(X+Y>=y)?(y-Y):(0);
next = pair<int,int>(x_, ry);
if(hash.find(next)==hash.end())
hash.insert(next), q.push_back(next);
next = pair<int,int>(rx, y_);
if(hash.find(next)==hash.end())
hash.insert(next), q.push_back(next);
}
}
return false;
}
};