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

 

解答:

数学方法不考虑,只说正常解法。想一下当前我们的两个水壶水量为cur_x,cur_y。我们下一步有几种做法:(1):装满水壶1或者2  (2):清空水壶1或2  (3):水壶1给2倒水/水壶2给1倒水

那么显然要一步步搜索可能的所有状态,那么是用DFS还是BFS呢?显然我们只要找到了一个解就可以返回。考虑一下要求的解,不像是那种递归到底才能找到的解,而是一个经过有限次就能够达到的解。所以考虑用BFS,这样经过少数轮次就应该可以找到解。

当然对于计算过的状态,必须用一个状态表记录下来。我们使用unordered_map< pair<int,int> >来存储状态,但pair<int,int>不是基本类型,我们需要自己写对应的hash函数,不懂的可以看这里:https://www.cnblogs.com/FdWzy/p/12542840.html

代码:

class Solution {
public:
    struct hs{
        size_t operator()(const pair<int,int>& x)const{
            return hash<int>()(x.first) ^ hash<int>()(x.second);
        }
    };
    bool canMeasureWater(int x, int y, int z) {
        if(x+y<z){
            return false;
        }
        unordered_set<pair<int,int>,hs> visited;
        int cur_x=x,cur_y=y;
        queue<pair<int,int> > que;
        que.push(make_pair(cur_x,cur_y));
        visited.insert(make_pair(cur_x,cur_y));
        while(not que.empty()){
            cur_x=que.front().first,cur_y=que.front().second;
            que.pop();
            if(cur_x==z or cur_y==z or cur_x+cur_y==z){
                return true;
            }
            // cout<<cur_x<<" "<<cur_y<<endl;
            //装满x或y:
            if(visited.count(make_pair(x,cur_y)) == 0){
                que.push(make_pair(x,cur_y));
                visited.insert({x,cur_y});
            }
            if(visited.count(make_pair(cur_x,y)) == 0){
                que.push(make_pair(cur_x,y));
                visited.insert({cur_x,y});
            }
            //清空x或y:
            if(visited.count(make_pair(0,cur_y)) == 0){
                que.push(make_pair(0,cur_y));
                visited.insert({0,cur_y});
            }
            if(visited.count(make_pair(cur_x,0)) == 0){
                que.push(make_pair(cur_x,0));
                visited.insert({cur_x,0});
            }
            //x给y倒水 或 y给x倒水
            int x_to_y=min(cur_x,y-cur_y),y_to_x=min(cur_y,x-cur_x);
            if(visited.count(make_pair(cur_x-x_to_y,cur_y+x_to_y)) == 0){
                que.push(make_pair(cur_x-x_to_y,cur_y+x_to_y));
                visited.insert({cur_x-x_to_y,cur_y+x_to_y});
            }
            if(visited.count(make_pair(cur_x+y_to_x,cur_y-y_to_x)) == 0){
                que.push(make_pair(cur_x+y_to_x,cur_y-y_to_x));
                visited.insert({cur_x+y_to_x,cur_y-y_to_x});
            }
        }
        return false;
    }
};

 

posted @ 2020-03-22 12:15  NeoZy  阅读(157)  评论(0编辑  收藏  举报