1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
""" 糖果逻辑题生成器 以"真实最小界"为核心,每次随机生成一道具体的糖果题,并输出 题目 / 解答 / 证明。 """ import random
FLAVORS = [ "苹果", "桃子", "西瓜", "草莓", "葡萄", "蓝莓", "柠檬", "橙子", "芒果", "荔枝", "菠萝", "樱桃", "香蕉", "椰子", "榴莲", "猕猴桃", "杨梅", "枇杷", "山楂", "桑葚", "石榴", "柚子", "蜜瓜", "杏仁", ]
SHAPES = [ "圆形", "五角星形", "三角形", "爱心形", "正方形", "六边形", "菱形", "月牙形", "水滴形", "花朵形", ]
def pick_flavors(n=3): return random.sample(FLAVORS, n)
def pick_shapes(n=2): return random.sample(SHAPES, n)
def rand_counts(): return [random.randint(1, 9) for _ in range(6)]
def true_answer(a, b, c, d, e, f): m = (a + e + 1) + (d + f + 1) n = (c + e + 1) + (b + f + 1) R1 = max(a, c) + e + f + 2 R4 = max(b, d) + e + f + 2 return min(R1, R4, m, n), (R1, R4, m, n)
def best_strategy(a, b, c, d, e, f): """返回 (cost, 描述, 两个形状各自摸几个) 中最优的那套""" R1 = (max(a, c) + e + f + 2, "R1", (max(a, c) + e + 1, f + 1)) R4 = (max(b, d) + e + f + 2, "R4", (e + 1, max(b, d) + f + 1)) m = ((a + e + 1) + (d + f + 1), "m", (a + e + 1, d + f + 1)) n = ((c + e + 1) + (b + f + 1), "n", (c + e + 1, b + f + 1)) return min([R1, R4, m, n], key=lambda t: t[0])
def generate_puzzle(): f1, f2, f3 = pick_flavors() s1, s2 = pick_shapes() a, b, c, d, e, f = rand_counts() return dict(f1=f1, f2=f2, f3=f3, s1=s1, s2=s2, a=a, b=b, c=c, d=d, e=e, f=f)
def render(p): f1, f2, f3 = p["f1"], p["f2"], p["f3"] s1, s2 = p["s1"], p["s2"] a, b, c, d, e, f = p["a"], p["b"], p["c"], p["d"], p["e"], p["f"] ans, _ = true_answer(a, b, c, d, e, f) cost, tag, (r1, r2) = best_strategy(a, b, c, d, e, f)
lines = [] lines.append("=" * 62) lines.append("【题目】") para = (f"想象一个黑袋子,里面装着三种口味的糖果:{f1}味、{f2}味和{f3}味。" f"每种糖果又有两种形状:{s1}和{s2}。" f"最关键的设定是,形状不同,手感能摸出来,也就是我们可以通过触觉区分是{s1}还是{s2}," f"但尝出来是什么味得拿出来后或者吃了才知道,光靠摸是永远猜不出口味的。" f"具体的数量是硬指标,{f1}味的{s1}有{a}个、{s2}有{b}个;" f"{f2}味的{s1}有{c}个、{s2}有{d}个;" f"{f3}味的{s1}有{e}个、{s2}有{f}个。" f"为了百分之百保证,你最少需要从袋子里摸出多少个糖果," f"才能确保手里同时拥有“不同形状的{f1}味和{f2}味的糖”?") lines.append(para) lines.append("")
lines.append("【解答】") lines.append(f"最少摸出 **{ans}** 个糖果。") lines.append(f"具体做法(最优策略 {tag}):摸 {r1} 个{s1} + 摸 {r2} 个{s2},共 {cost} 个。") lines.append("")
lines.append("【证明】") lines += proof(p) lines.append("=" * 62) return "\n".join(lines)
def proof(p): f1, f2, f3 = p["f1"], p["f2"], p["f3"] s1, s2 = p["s1"], p["s2"] a, b, c, d, e, f = p["a"], p["b"], p["c"], p["d"], p["e"], p["f"] ans, (R1, R4, m, n) = true_answer(a, b, c, d, e, f) cost, tag, (r1, r2) = best_strategy(a, b, c, d, e, f)
L = [] L.append(f"设摸 {r1} 个{s1}、q 个{s2}。目标是保证“{f1}味与{f2}味、形状不同”,") L.append(f"即至少出现以下两种组合之一:") L.append(f" ① {s1}的{f1}味 与 {s2}的{f2}味;") L.append(f" ② {s2}的{f1}味 与 {s1}的{f2}味。") L.append("") L.append(f"【第一步:安全条件】若摸了 r 个{s1}、q 个{s2},反过来思考“什么时候会失败”。") L.append(f"失败当且仅当存在某种取法,使得 (摸不到{f1}味{s1} 或 摸不到{f2}味{s2}) 且 " f"(摸不到{f1}味{s2} 或 摸不到{f2}味{s1})。") L.append(f"逐项排除后,保证成功的充要条件是同时满足:") L.append(f" r ≥ e+1 = {e+1}(否则可能全是{f3}味{s1});") L.append(f" q ≥ f+1 = {f+1}(否则可能全是{f3}味{s2});") L.append(f" ( r ≥ c+e+1 = {c+e+1} 或 q ≥ d+f+1 = {d+f+1} );") L.append(f" ( r ≥ a+e+1 = {a+e+1} 或 q ≥ b+f+1 = {b+f+1} )。") L.append("") L.append(f"【第二步:最优值】目标为最小化 r+q,最优解必然落在下列四个角点之一:") L.append(f" R1:r=max(a,c)+e+1={max(a,c)+e+1}、q=f+1={f+1},花费 {R1};") L.append(f" R4:r=e+1={e+1}、q=max(b,d)+f+1={max(b,d)+f+1},花费 {R4};") L.append(f" m :r=a+e+1={a+e+1}、q=d+f+1={d+f+1},花费 {m};") L.append(f" n :r=c+e+1={c+e+1}、q=b+f+1={b+f+1},花费 {n}。") L.append(f"取最小:min(R1,R4,m,n) = min({R1},{R4},{m},{n}) = **{ans}**,由策略 {tag} 达到。") L.append("") L.append(f"【第三步:可行性验证(以 {tag} 为例)】") t, rr, qq = tag, r1, r2 if t == "R1": L.append(f"摸 {rr} 个{s1}:{s1}中{f3}味仅 {e} 个,非{f1}味的只有 {c+e} 个、非{f2}味的只有 {a+e} 个,") L.append(f" 摸 {max(a,c)+e+1} 个必然同时摸到{f1}味与{f2}味的{s1};") L.append(f"摸 {qq} 个{s2}:{s2}中{f3}味仅 {f} 个,摸 {f+1} 个必含{f1}味或{f2}味;") L.append(f"把该{f1}味/{f2}味{s2}与相反的{s1}目标味配对,即得形状不同的{f1}+{f2}。") elif t == "R4": L.append(f"摸 {rr} 个{s1}必含{f1}味或{f2}味;") L.append(f"摸 {qq} 个{s2}:{s2}中{f3}味仅 {f} 个,非{f1}味只有 {d+f} 个、非{f2}味只有 {b+f} 个,") L.append(f" 摸 {max(b,d)+f+1} 个必然同时摸到{f1}味与{f2}味的{s2};") L.append(f"把两形状的目标味交叉配对,即得形状不同的{f1}+{f2}。") elif t == "m": L.append(f"摸 {rr} 个{s1}必含{f2}味(非{f2}味仅 {a+e} 个);") L.append(f"摸 {qq} 个{s2}必含{f1}味(非{f1}味仅 {d+f} 个);") L.append(f"于是必有 {s2}的{f1}味 + {s1}的{f2}味,形状不同。") else: L.append(f"摸 {rr} 个{s1}必含{f1}味(非{f1}味仅 {c+e} 个);") L.append(f"摸 {qq} 个{s2}必含{f2}味(非{f2}味仅 {b+f} 个);") L.append(f"于是必有 {s1}的{f1}味 + {s2}的{f2}味,形状不同。") L.append("") L.append(f"【第四步:为什么更少不行】若总数小于 {ans},r+q≤{ans-1},") L.append(f"则四个角点条件必有至少一个被破坏,存在可构造的失败取法,故无法百分之百保证。") return L
if __name__ == "__main__": random.seed() print(render(generate_puzzle()))
|