数字猜谜:二分法 VS 随机猜,效率真实对比
一、故事内容
小明和小红在玩一个数字猜谜游戏:
小明说:"我每次都随机猜,反正总能猜中。"
小红说:"我用二分法来猜:第一次先猜 50;如果提示大了,就在 1 到 49 继续猜中间;如果提示小了,就在 51 到 100 继续猜中间。每次都把范围缩小一半,所以通常会更快。"
到底谁更高效? 这个问题可以用数学分析 + Python 模拟来验证。
二、对应的数学知识
1. 数字猜谜反馈函数
设目标数字是 ,当前猜测是 ,则反馈规则是:
2. 二分法思想
在区间 [1, 100] 内找数字时,每次猜中点:
每猜一次,搜索区间大约缩小一半,所以猜测次数增长很慢。 理论上,大约需要做下面这么多次对半缩小:
3. 随机猜测思想
随机猜法每次在当前可能范围内随机取一个数。它也能利用"大了/小了"来缩小区间,但不会像二分法那样稳定地对半分,猜测次数通常更大、波动也更明显。
三、数学建模
问题分析
模型步骤
- 设计反馈函数
judge_guess(target, guess) target为目标数,guess为当前猜测,返回"大了"、"小了"或"正确" - 实现二分法猜数函数
binary_guess_count(target) 返回二分法猜中目标数的次数 - 实现随机猜数函数
random_guess_count(target) 返回随机猜中目标数的次数 - 随机生成 10 个目标数,分别用两种方法猜测,记录每次猜测次数
四、Python 代码实现
import random
defjudge_guess(target, guess):
"""
target: 目标数字
guess: 当前猜测数字
比较猜测值与目标值。
返回:"大了"、"小了" 或 "正确"
"""
if guess > target:
return"大了"
if guess < target:
return"小了"
return"正确"
defbinary_guess_count(target, low=1, high=100):
"""
使用二分法猜中目标数字,返回猜测次数。
target: 目标数字
low: 当前可能的最小值 默认1
high: 当前可能的最大值 默认100
"""
count = 0
left, right = low, high
while left <= right:
count += 1
# 每次猜当前区间的中间值
mid = (left + right) // 2
result = judge_guess(target, mid)
if result == "正确":
return count
elif result == "大了":
# 猜大了,说明目标在左边区间
right = mid - 1
else:
# 猜小了,说明目标在右边区间
left = mid + 1
return count
defrandom_guess_count(target, low=1, high=100):
"""
使用随机法猜中目标数字,返回猜测次数。
每次都在当前可能区间内随机猜一个数。
"""
count = 0
left, right = low, high
while left <= right:
count += 1
# 虽然是随机猜,但仍然只在当前可能范围内猜
guess = random.randint(left, right)
result = judge_guess(target, guess)
if result == "正确":
return count
elif result == "大了":
# 猜大了,排除 guess 以及它右边的数
right = guess - 1
else:
# 猜小了,排除 guess 以及它左边的数
left = guess + 1
return count
# 运行对比实验实现
defrun_compare(trials=10, low=1, high=100):
"""
模拟 trials 组测试,比较二分法与随机法。
使用同一批目标数字,保证对比公平。
trials: 实验组数次数
low: 目标数字的最小值
high: 目标数字的最大值
"""
# 生成一批随机目标数字,保证两种方法对比使用同一批目标
targets = [random.randint(low, high) for _ in range(trials)]
# 记录两种方法的猜测次数
binary_counts = [] # 二分法猜测次数
random_counts = [] # 随机法猜测次数
for target in targets:
# 对同一个目标数,分别测试两种方法
b_count = binary_guess_count(target, low, high)
r_count = random_guess_count(target, low, high)
# 记录结果
binary_counts.append(b_count)
random_counts.append(r_count)
# 返回目标数列表和两种方法的猜测次数列表
return targets, binary_counts, random_counts
if __name__ == "__main__":
# 设置实验组数默认10次
trials = 10
# 运行 10 组实验,并记录两种方法各自的猜测次数
targets, binary_counts, random_counts = run_compare(trials=trials)
print("=" * 64)
print("数字猜谜效率对比:二分法 VS 随机猜")
print("=" * 64)
print("轮次 目标数 二分法次数 随机法次数")
# 输出每组实验的结果
for i in range(trials):
print(f"{i + 1:>2}{targets[i]:>3}{binary_counts[i]:>3}{random_counts[i]:>3}")
# 计算两种方法的平均猜测次数 并总结
avg_binary = sum(binary_counts) / trials
avg_random = sum(random_counts) / trials
print("-" * 64)
print(f"二分法平均次数:{avg_binary:.2f}")
print(f"随机法平均次数:{avg_random:.2f}")
if avg_binary < avg_random:
print("结论:二分法整体更高效。")
elif avg_binary > avg_random:
print("结论:随机法整体更高效(本次实验偶然结果)。")
else:
print("结论:两者平均次数相同(本次实验偶然结果)。")
五、示例输出(每次随机过程略有不同)
================================================================
数字猜谜效率对比:二分法 VS 随机猜
================================================================
轮次 目标数 二分法次数 随机法次数
1 82 6 7
2 15 5 8
3 4 6 7
4 95 6 9
5 36 7 9
6 32 6 6
7 29 6 11
8 18 4 5
9 95 6 11
10 14 7 4
----------------------------------------------------------------
二分法平均次数:5.90
随机法平均次数:7.70
结论:二分法整体更高效。
六、总结
- 二分法次数通常在 4-7 次之间,平均约 6 次,没有大幅波动,效率稳定。
- 随机猜测次数波动较大,可能在 4-11 次之间,平均约 7-8 次,效率不稳定。
- 通过同一批 10 个目标数的模拟对比,可以直观看到两种策略的效率差异。
这个实验说明:在有明确"大了/小了"反馈时,使用更有结构的策略(如二分法)通常比纯随机更快。