换酒定理构造了一种换酒方法,从而证明了方程的解是有效可靠的
问题引入
餐馆的啤酒售价为5元一瓶。近期节日有促销活动,喝完啤酒后,可以用5个空瓶或10个瓶盖换购一瓶啤酒。此外,消费满100元可以再送一瓶啤酒。现有200元,最多可以喝多少瓶啤酒?
方法1
根据价值守恒
下表为将酒喝完后的状态,每行中 钱+盖+瓶+酒 的总价值为210。
最终喝了58瓶酒,余8个盖和3个瓶。
| 步骤 | 操作 | 钱 | 盖数Aₙ | 瓶数Bₙ | 累计酒数Cₙ |
|---|---|---|---|---|---|
| 0 | 送的酒换成钱 | 210 | 0 | 0 | 0 |
| 1 | 210元买酒 | 0 | 42 | 42 | 42 |
| 2 | 换酒 | 0 | 14 | 14 | 42+(4+8) |
| 3 | 换酒 | 0 | 7 | 7 | 42+(4+8)+(1+2) |
| 4 | 换酒 | 0 | 8 | 3 | 42+(4+8)+(1+2)+(0+1)=58 |
| 5 | 借老板2瓶酒 | 0 | 10 | 5 | 58+2=60 |
| 6 | 还老板2瓶酒 | 0 | 0 | 0 | 60 |
Aₙ、Bₙ、Cₙ分别为第n步盖、瓶、酒的情况。
其中:
- [a/b] 为 a除以b的商
- a mod b 为 a除以b的余数
A₁=42;B₁=42;C₁=42;Dₙ=ΔCₙ
Dₙ 是每次换酒喝到的酒数
Aₙ = Aₙ₋₁ mod 10 + Dₙ //上步余下的盖+新盖 Bₙ = Bₙ₋₁ mod 5 + Dₙ //上步余下的瓶+新瓶 Dₙ = [Aₙ₋₁/10] + [Bₙ₋₁/5] //上步盖换的酒+上步瓶换的酒
方法2
把钱、盖、瓶、酒全部转换为同样的单位——元。
把每一个条件转换为1个方程。
约定
- 1元=1元
- 1盖=x元
- 1酒=y元
- 1瓶=z元
若初始资产为A元,则答案为 A/y。
方程组
A = 42(x+y+z) 10x = x+y+z 5z = x+y+z 5 = x+y+z
联立上面4个方程可得 A/y=60,可以喝60瓶酒。
解方程
安装符号计算库sympy:
pip install sympy
编码:
from sympy import symbols, linsolve
# 定义符号变量
# 1元=1元
# 1盖=x元
# 1酒=y元
# 1瓶=z元
# 若初始资产为A元,则答案为 A/y
x, y, z, A = symbols('x y z A')
# 创建线性方程组
eq1 = 42*(x+y+z) - A
eq2 = x + y + z - 10*x
eq3 = x + y + z - 5*z
eq4 = x + y + z - 5
# 求解线性方程组
result = linsolve([eq1, eq2, eq3, eq4], (x, y, z, A))
# 提取解集中的值
rx,ry,rz,rA = result.args[0]
# 打印解
print(f"1盖={rx}元")
print(f"1酒={ry}元")
print(f"1瓶={rz}元")
print(f"共可以喝 {rA/ry} 瓶酒")
1盖=1/2元
1酒=7/2元
1瓶=1元
共可以喝 60 瓶酒
方法3
与方法2类似,把钱、盖、瓶、酒全部转换为同样的单位——瓶酒盖(U)。
- 1瓶酒盖=1瓶+1酒+1盖=1U
- 1元=0.2U
- 1盖=0.1U
- 1瓶=0.2U
- 1酒=1U-1盖-1瓶=(1-0.1-0.2)U=0.7U
初始资产=210元=42U
喝的酒数=初始资产/1酒=42U/0.7U=60
换酒定理
酒换干净的充要条件是:初始资产可换整瓶酒b,并且方法2的解s=A/y为整数。
如果没有这个换酒定理,上面的方程组解法是不严谨的,并有可能是错的。
下面的换法是为借老板s-b瓶酒一步到位,不用换来换去了。换酒定理回答了方法2算出的解是否可靠,在现实中是否可操作。
下面构造换法:
约定:
- P1: 初始资产可换b瓶酒
- P2: 方法2的解A/y=s
- P3: 借老板t瓶酒
初始资产+借老板的资产=喝进肚子酒的资产+还老板的资产
b(x+y+z) + t(x+y+z) = sy + s(x+z)
只要t是整数,就存在换法
t=s-b
因为s是喝的酒数, 现实中s必须为整数
所以s和b都为整数才能换干净
根据换酒定理构造的换酒步骤如下:
- 先喝下210元买的42瓶酒
- 借老板18瓶酒,并喝下,此时已经喝下了60瓶酒
- 把手上的60个瓶和60个盖子还给老板,抵消借老板的18瓶酒