引子 有这么一道问题:
现有一瓶 10 ml 的水,和两个容量分别为 7 ml 和 3 ml 的空水瓶,
如何将 10 ml 的水平分成两个 5 ml ?
遇到一个问题,要看作一类问题,将这一类问题解决了,这一个问题就解决了,
以后遇到这样的每一个问题都解决了。
这个问题给出了具体的数值,我们可以替换为符号,然后用代数方法求解。
为了方便,将这类问题记为“三瓶水问题”。
数学模型 考虑一个二元组 ( c , w ) (c, w) ( c , w ) 作为水瓶,其中 c c c 是容量,w w w 是水量。
有 3 个这样的瓶子,分别记为 B 0 = ( c 0 , w 0 ) B_0=(c_0, w_0) B 0 = ( c 0 , w 0 ) 、B 1 = ( c 1 , w 1 ) B_1=(c_1, w_1) B 1 = ( c 1 , w 1 ) 、B 2 = ( c 2 , w 2 ) B_2=(c_2, w_2) B 2 = ( c 2 , w 2 ) ,
满足
{ c , w ∈ N ; c ≠ 0 c 0 = c 1 + c 2 = w 0 + w 1 + w 2 0 ≤ w 0 ≤ c 0 , 0 ≤ w 1 ≤ c 1 , 0 ≤ w 2 ≤ c 2
\left\{
\begin{aligned}
&c,\ w\in \mathbb{N};\ c\neq 0\\
&c_0=c_1+c_2=w_0+w_1+w_2\\
&0\leq w_0\leq c_0,\ 0\leq w_1\leq c_1,\ 0\leq w_2\leq c_2
\end{aligned}
\right.
⎩ ⎨ ⎧ c , w ∈ N ; c = 0 c 0 = c 1 + c 2 = w 0 + w 1 + w 2 0 ≤ w 0 ≤ c 0 , 0 ≤ w 1 ≤ c 1 , 0 ≤ w 2 ≤ c 2 倒水操作定义为关于 w w w 的加减运算,例如从 B 1 B_1 B 1 向 B 2 B_2 B 2 倒水,先计算 B 2 B_2 B 2 剩余容量,
如果大于等于 B 1 B_1 B 1 水量,则 B 2 B_2 B 2 水量加上 B 1 B_1 B 1 水量,然后 B 1 B_1 B 1 水量置零,
否则 B 1 B_1 B 1 水量减去 B 2 B_2 B 2 剩余容量,然后 B 2 B_2 B 2 水量置满。
程序模拟 以上数学模型可以表示为以下程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from dataclasses import dataclass
@dataclass
class Bottle :
capacity : int
water : int
def __post_init__ ( self ):
# check the constraints
pass
def pour ( bottle1 : Bottle , bottle2 : Bottle ) -> None :
# pour from bottle1 to bottle2
left_capacity = bottle2 . capacity - bottle2 . water
if left_capacity >= bottle1 . water :
bottle2 . water += bottle1 . water
bottle1 . water = 0
else :
bottle1 . water -= left_capacity
bottle2 . water = bottle2 . capacity
Copy 数学归纳 从根本上解决问题还是需要数学方法,但是由于当前数学水平有限,
先从简单问题总结归纳得到猜想规律,以后有机会再做验证研究。
三瓶水问题可以拓展为分出 [ 0 , c 0 ] [0,c_0] [ 0 , c 0 ] 之间任意整数的水量。
显然 0 , c 0 , c 1 , c 2 0,\ c_0,\ c_1,\ c_2 0 , c 0 , c 1 , c 2 的水量一定可以得到,则
只需考虑 [ 1 , c 0 − 1 ] [1,c_0-1] [ 1 , c 0 − 1 ] 之间的水量(不包含 c 1 , c 2 c_1,\ c_2 c 1 , c 2 )。
另外易证,如果可以得到 x x x 的水量,一定可以得到 c 0 − x c_0-x c 0 − x 的水量,则
只需考虑 [ 1 , ⌊ c 0 / 2 ⌋ ] [1,\lfloor c_0/2\rfloor] [ 1 , ⌊ c 0 /2 ⌋] 之间的水量(不包含 c 1 , c 2 c_1,\ c_2 c 1 , c 2 )。
简单例子 例 1
c 0 = 5 , c 1 = 2 , c 2 = 3 c_0=5,\ c_1=2,\ c_2=3 c 0 = 5 , c 1 = 2 , c 2 = 3 ,考虑 1 1 1 ,显然可以得到。c 0 = 5 , c 1 = 1 , c 2 = 4 c_0=5,\ c_1=1,\ c_2=4 c 0 = 5 , c 1 = 1 , c 2 = 4 ,考虑 2 2 2 ,也可得到。另外可以观察到,如果 c 1 c_1 c 1 或者 c 2 c_2 c 2 为 1 1 1 ,则所有水量一定可以得到。
例 2
c 0 = 6 , c 1 = 2 , c 2 = 4 c_0=6,\ c_1=2,\ c_2=4 c 0 = 6 , c 1 = 2 , c 2 = 4 ,考虑 1 , 3 1,\ 3 1 , 3 ,无法得到。c 0 = 6 , c 1 = 3 , c 2 = 3 c_0=6,\ c_1=3,\ c_2=3 c 0 = 6 , c 1 = 3 , c 2 = 3 ,考虑 1 , 2 1,\ 2 1 , 2 ,无法得到。例 3
c 0 = 7 , c 1 = 2 , c 2 = 5 c_0=7,\ c_1=2,\ c_2=5 c 0 = 7 , c 1 = 2 , c 2 = 5 ,考虑 1 , 3 1,\ 3 1 , 3 ,可以得到。c 0 = 7 , c 1 = 3 , c 2 = 4 c_0=7,\ c_1=3,\ c_2=4 c 0 = 7 , c 1 = 3 , c 2 = 4 ,考虑 1 , 2 1,\ 2 1 , 2 ,可以得到。思考与猜想 所有能得到的数都是通过 c 0 , c 1 , c 2 c_0,\ c_1,\ c_2 c 0 , c 1 , c 2 以及它们的和差之间的加减运算得到的。
c 0 c_0 c 0 只能作为被减数,用于计算某一水量 x x x 的补水量,即 c 0 − x c_0-x c 0 − x 。c 1 c_1 c 1 和 c 2 c_2 c 2 只能用大数 c 1 c_1 c 1 减去小数 c 2 c_2 c 2 得到 x x x 。如果 x x x 是一个新值,则可以与 c 2 c_2 c 2 做减法,尝试与 c 1 c_1 c 1 做加法,否则结束。 新值即属于考虑集合但之前还未得到的值。
大胆的猜测 :考虑集合内属于 c 0 , c 1 , c 2 c_0,\ c_1,\ c_2 c 0 , c 1 , c 2 最大公约数的值一定可以得到。
方法可能比较复杂,但一定存在,整体思路如上 3 个步骤。
该猜测在简单问题上已验证,但还未得到严格的数学证明。
附:解决引子问题 首先定义水瓶 B 0 = ( 10 , 10 ) , B 1 = ( 7 , 0 ) , B 2 = ( 3 , 0 ) B_0=(10, 10),\ B_1=(7, 0),\ B_2=(3, 0) B 0 = ( 10 , 10 ) , B 1 = ( 7 , 0 ) , B 2 = ( 3 , 0 ) ,
然后倒水,以下左边是方向,右边是完成状态:
B 0 ⇒ B 1 B 0 = ( 10 , 3 ) , B 1 = ( 7 , 7 ) , B 2 = ( 3 , 0 ) B 1 ⇒ B 2 B 0 = ( 10 , 3 ) , B 1 = ( 7 , 4 ) , B 2 = ( 3 , 3 ) B 2 ⇒ B 0 B 0 = ( 10 , 6 ) , B 1 = ( 7 , 4 ) , B 2 = ( 3 , 0 ) B 1 ⇒ B 2 B 0 = ( 10 , 6 ) , B 1 = ( 7 , 1 ) , B 2 = ( 3 , 3 ) B 2 ⇒ B 0 B 0 = ( 10 , 9 ) , B 1 = ( 7 , 1 ) , B 2 = ( 3 , 0 ) B 1 ⇒ B 2 B 0 = ( 10 , 9 ) , B 1 = ( 7 , 0 ) , B 2 = ( 3 , 1 ) B 0 ⇒ B 1 B 0 = ( 10 , 2 ) , B 1 = ( 7 , 7 ) , B 2 = ( 3 , 1 ) B 1 ⇒ B 2 B 0 = ( 10 , 2 ) , B 1 = ( 7 , 5 ) , B 2 = ( 3 , 3 )
\begin{align}
&B_0\Rightarrow B_1&B_0=(10,3),\ B_1=(7,7),\ B_2=(3,0)\\
&B_1\Rightarrow B_2&B_0=(10,3),\ B_1=(7,4),\ B_2=(3,3)\\
&B_2\Rightarrow B_0&B_0=(10,6),\ B_1=(7,4),\ B_2=(3,0)\\
&B_1\Rightarrow B_2&B_0=(10,6),\ B_1=(7,1),\ B_2=(3,3)\\
&B_2\Rightarrow B_0&B_0=(10,9),\ B_1=(7,1),\ B_2=(3,0)\\
&B_1\Rightarrow B_2&B_0=(10,9),\ B_1=(7,0),\ B_2=(3,1)\\
&B_0\Rightarrow B_1&B_0=(10,2),\ B_1=(7,7),\ B_2=(3,1)\\
&B_1\Rightarrow B_2&B_0=(10,2),\ B_1=(7,5),\ B_2=(3,3)\\
\end{align}
B 0 ⇒ B 1 B 1 ⇒ B 2 B 2 ⇒ B 0 B 1 ⇒ B 2 B 2 ⇒ B 0 B 1 ⇒ B 2 B 0 ⇒ B 1 B 1 ⇒ B 2 B 0 = ( 10 , 3 ) , B 1 = ( 7 , 7 ) , B 2 = ( 3 , 0 ) B 0 = ( 10 , 3 ) , B 1 = ( 7 , 4 ) , B 2 = ( 3 , 3 ) B 0 = ( 10 , 6 ) , B 1 = ( 7 , 4 ) , B 2 = ( 3 , 0 ) B 0 = ( 10 , 6 ) , B 1 = ( 7 , 1 ) , B 2 = ( 3 , 3 ) B 0 = ( 10 , 9 ) , B 1 = ( 7 , 1 ) , B 2 = ( 3 , 0 ) B 0 = ( 10 , 9 ) , B 1 = ( 7 , 0 ) , B 2 = ( 3 , 1 ) B 0 = ( 10 , 2 ) , B 1 = ( 7 , 7 ) , B 2 = ( 3 , 1 ) B 0 = ( 10 , 2 ) , B 1 = ( 7 , 5 ) , B 2 = ( 3 , 3 )