题目链接
额,先声明一下这两种方法都会超时,但是从解题思路上来说DFS和BFS确实是一种方向。所以实现了一下。(毕竟想不到用GCD做)。想AC的请看这里
DFS
- 用dfs做其实就是要确定状态,转移到下一状态以及回溯到上一状态。
我选的状态是(jug0, jug1, jug2),分别代表三个罐子内的水量。为什么是三个罐子?题目中“an infinite amount of water”可以看做是一个有无限水、容量也是无限的罐子。这样问题就成了三个罐子之间的倒水问题,个人感觉问题简化了一些。 - 转移到下一状态。共有六种情况,需要根据两只罐子的情况进行转移。
- 回溯。在转移到下一状态时需要就行判断,这就让回溯的时候很难知道回溯到什么状态。用双向队列可以很好地解决这个问题:转移到下一状态时,把下一状态加入到队列中;回溯的时候再将它移除就可以。
// C# Time Limit Exceeded
public class Solution
{
struct State
{
public State(long x, long y, long z)
{
jug = new long[3] {x, y, z };
}
public long[] jug;
//对倒水的合法性进行判断:倒出的罐子必须有水,倒入的罐子不能是满的
public bool IsValid(int from, int to)
{
return jug[from] != 0 && jug[to] != capicity[to];
}
public void Dump(int from, int to)
{
long dumpWater = capicity[to] - jug[to];
if (jug[from] >= dumpWater)
{
jug[from] -= dumpWater;
jug[to] += dumpWater;
}
else
{
jug[to] += jug[from];
jug[from] = 0;
}
}
}
//记录状态,防止重复访问节点
List<State> states = new List<State>();
static public long[] capicity = new long[3];
public long target = 0;
public bool CanMeasureWater(int x, int y, int z)
{
capicity[0] = x;
capicity[1] = y;
capicity[2] = long.MaxValue;//用long.MaxValue来假装是一个无穷大的罐子
target = z;
State s = new State(0, 0, int.MaxValue);//用int.MaxValue假装是个有无限多水的罐子
states.Add(s);
return Work();
}
private bool Work()
{
State s = states[states.Count - 1];
if (s.jug[0] + s.jug[1] == target)
{
return true;
}
for (int from = 0;from < 3;++from)
for (int to = 0; to < 3; ++to)
{
if (from != to)
{
State next = new State(s.jug[0], s.jug[1], s.jug[2]);
if (next.IsValid(from, to))
{
next.Dump(from, to);
//查看当前队列中是否有next
bool isContain = states.Exists(x => x.jug[0] == next.jug[0] && x.jug[1] == next.jug[1] && x.jug[2] == next.jug[2]);
if (isContain == false)
{
states.Add(next);
if (Work()) return true;//转移到下一状态
states.RemoveAt(states.Count - 1);//回溯
}
}
}
}
return false;
}
}
BFS
逛讨论区发现有人用BFS写,不过也是超时了。原贴链接:Breadth-First-Search-with-explanation
//python Time Limit Exceeded
class Solution(object):
def canMeasureWater(self, x, y, z):
"""
:type x: int
:type y: int
:type z: int
:rtype: bool
"""
if x > y:
temp = x;
x = y;
y = temp;
if z > x + y:
return False;
# set the initial state will empty jars;
queue = [(0, 0)];
visited = set((0, 0));
while len(queue) > 0:
a, b = queue.pop(0);
if a + b == z:
return True;
states = set()
states.add((x, b)) # fill jar x;
states.add((a, y)) # fill jar y;
states.add((0, b)) # empty jar x;
states.add((a, 0)) # empty jar y;
states.add((min(x, b + a), 0 if b < x - a else b - (x - a))) # pour jar y to x;
states.add((0 if a + b < y else a - (y - b), min(b + a, y))) # pour jar x to y;
for state in states:
if state in visited:
continue;
queue.append(state)
visited.add(state);
return False;