Skip to content

Commit a670991

Browse files
lvguofeng1303azl397985856
authored andcommittedSep 16, 2019
feat: 每日一题 - 2019-09-15 - 水壶问题(#170) (#175)
* feat: 每日一题 - 2019-09-15 - 水壶问题(#170) * feat: bfs解法,部分格式问题
1 parent 78eab1b commit a670991

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed
 

‎daily/2019-09-15.md

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# 毎日一题 - 水壶问题
2+
3+
## 信息卡片
4+
5+
* 时间:2019-09-15
6+
* 题目链接:https://leetcode-cn.com/problems/water-and-jug-problem/
7+
* tag:`Math`
8+
## 题目描述
9+
```
10+
给你一个装满水的 8 升满壶和两个分别是 5 升、3 升的空壶,请想个优雅的办法,使得其中一个水壶恰好装 4 升水,每一步的操作只能是倒空或倒满。
11+
```
12+
13+
## 参考答案
14+
15+
1.数学分析解答
16+
17+
上面的问题是一个特例,我们可以抽象为[leetcode-365-水壶问题](https://leetcode-cn.com/problems/water-and-jug-problem/)
18+
```
19+
有两个容量分别为 x升 和 y升 的水壶(壶1,壶2)以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水?
20+
```
21+
22+
解题核心思路(x < y,即壶1容量小于壶2,x == y的情况后面讨论):
23+
24+
1. 将壶2倒满,往壶1倒入至满。
25+
2. 若壶1满,记录当前壶2中新水量。壶1倒出,将壶2中剩余的继续往壶1中倒入;(当壶1满,继续此操作,并记录当前壶2中新水量nw, 若此新水量已被记录,则)。
26+
3. 若出现壶1不满时(即此时壶2必空),重复操作1。
27+
28+
开辟一个新数组nws记录所有新水量,对任意nws[i],可构造的水量为nws[i],nws[i]+x,nws[i]+y。
29+
30+
(其实不需要新数组,因为数学上可以证明新水量的值循环周期呈现,故可以使用一个临时变量cur,当cur==x为终止条件)
31+
32+
数学证明新水量nw值是循环周期的:
33+
![1111](<https://raw.githubusercontent.com/lvguofeng1303/markdownimage/master/daily/%E6%B0%B4%E5%A3%B6%E9%97%AE%E9%A2%98/math%20prove.jpg>)
34+
35+
个别特殊情况考虑:
36+
37+
- x == z || y == z; **true**
38+
- x == 0 || x+y < z; **false**
39+
- x+y == z || z == 0; **true**
40+
41+
```c++
42+
class Solution {
43+
public:
44+
bool canMeasureWater(int x, int y, int z) {
45+
if(x > y) return canMeasureWater(y, x, z);
46+
if(x == z || y == z) return true;
47+
if(x == 0 || x+y < z) return false;
48+
if(x+y == z || z == 0) return true;
49+
int cur = y - x;
50+
while(cur != x){
51+
if(cur == z) return true;
52+
if(cur > x){
53+
if(cur + x == z) return true;
54+
cur = cur - x;
55+
}
56+
else{
57+
if(cur + y == z || cur + x == z) return true;
58+
cur = y - x + cur;
59+
}
60+
}
61+
return false;
62+
}
63+
};
64+
```
65+
66+
2.BFS
67+
68+
不仅可以计算是否能获取 z 升水,而且可以获得最少多少操作可获取 z 升水。(缺点,无法通过,因为需要太大的空间,需要申请一个三维数组记录状态)
69+
70+
核心思想就是状态转移问题:
71+
72+
壶0(x+y),壶1(x),壶2(y),壶0是本是无限大水池,同理于定义为大小为x+y的壶。用bfs的思想,使用一个队列记录所有新的状态。
73+
74+
对于任意状态(c,a,b),状态转移就是:
75+
76+
- 若c不为0,将壶0倒水入壶1或壶2;若a不为0,将壶1倒水入壶0或壶2;若b不为0,将壶2倒水入壶0或壶1;
77+
- 记录每个新状态,并入队,若此状态访问过则不入队。
78+
79+
特殊情况考虑同1。
80+
81+
```c++
82+
class Solution {
83+
public:
84+
struct state{
85+
int nums[3];
86+
state(int xy, int x, int y){
87+
nums[0] = xy;
88+
nums[1] = x;
89+
nums[2] = y;
90+
}
91+
};
92+
93+
state pour_water(state cur, int src, int det, int size[]){
94+
state ans = cur;
95+
int need_w = size[det] - cur.nums[det];
96+
if(need_w <= cur.nums[src]){
97+
ans.nums[det] += need_w;
98+
ans.nums[src] -= need_w;
99+
}
100+
else{
101+
ans.nums[det] += ans.nums[src];
102+
ans.nums[src] = 0;
103+
}
104+
return ans;
105+
}
106+
107+
bool canMeasureWater(int x, int y, int z) {
108+
if(x > y) return canMeasureWater(y, x, z); //
109+
if(x == z || y == z) return true;
110+
if(x == 0 || x+y < z) return false;
111+
if(x+y == z || z == 0) return true;
112+
int visited[x+y+1][x+1][y+1];
113+
int water_size[3] = {x+y, x, y};
114+
memset(visited, 0, sizeof(visited));
115+
state cur(x+y, 0, 0);
116+
queue<state> q;
117+
q.push(cur);
118+
int step = 0;
119+
while(!q.empty()){
120+
int size = q.size();
121+
while(size){
122+
state temp(0, 0, 0);
123+
cur = q.front();
124+
if(cur.nums[1] + cur.nums[2] == z) return true;
125+
visited[cur.nums[0]][cur.nums[1]][cur.nums[2]] = 1;
126+
q.pop();
127+
if(cur.nums[0] != 0){
128+
temp = pour_water(cur, 0, 1, water_size);
129+
if(visited[temp.nums[0]][temp.nums[1]][temp.nums[2]] != 1)
130+
q.push(temp);
131+
temp = pour_water(cur, 0, 2, water_size);
132+
if(visited[temp.nums[0]][temp.nums[1]][temp.nums[2]] != 1)
133+
q.push(temp);
134+
}
135+
if(cur.nums[1] != 0){
136+
temp = pour_water(cur, 1, 2, water_size);
137+
if(visited[temp.nums[0]][temp.nums[1]][temp.nums[2]] != 1)
138+
q.push(temp);
139+
temp = pour_water(cur, 1, 0, water_size);
140+
if(visited[temp.nums[0]][temp.nums[1]][temp.nums[2]] != 1)
141+
q.push(temp);
142+
}
143+
if(cur.nums[2] != 0){
144+
temp = pour_water(cur, 2, 1, water_size);
145+
if(visited[temp.nums[0]][temp.nums[1]][temp.nums[2]] != 1)
146+
q.push(temp);
147+
temp = pour_water(cur, 2, 0, water_size);
148+
if(visited[temp.nums[0]][temp.nums[1]][temp.nums[2]] != 1)
149+
q.push(temp);
150+
}
151+
size--;
152+
}
153+
step++;
154+
}
155+
return false;
156+
}
157+
};
158+
```
159+
160+
## 优秀解答
161+
162+
>暂缺

0 commit comments

Comments
 (0)