找钥匙问题

https://www.zhihu.com/question/307814660/answer/566825886

小明把钥匙丢了,只知道钥匙肯定丢在家里或者学校里。如果丢在了家里,在家里找一次能够找到的概率为a;如果丢在了学校里,在学校里找一次能够找到的概率为b。最初小明认为钥匙丢在家里的概率为p。问:小明应该采取什么策略来找钥匙才能够最快找到钥匙(寻找次数尽量少)?期望寻找次数是多少?

假如第一次在家里找,结果没有找到,钥匙依旧在家的概率为$p_1=\frac{p\times(1-a)}{1-p\times a}$
如果第一次在学校找,结果没找到,钥匙依旧在家的概率为$p_1=\frac{p}{1-(1-p)\times b}$

$$f(p)=min\{cost_{home},cost_{school}\}$$
$$cost_{home}=canfind\times1+(1-canfind)\times [1+f(p_1)]$$
$$cost_{school}=canfind\times1+(1-canfind)\times [1+f(p_1)]$$

其中canfind表示能够找到的概率, $p_1$ 表示经过一次寻找之后钥匙在家的概率。如果在家里找到了,那么只需要一步就能找到钥匙;如果没有找到,那么需要 $1+f(p_1)$步才能找到钥匙。

贪心法应该是对的
根据 $p\times a>(1-p)\times b$来决定去家里找还是学校找。
假如寻找次数为16步,那么所有的寻找序列构成一个深度为16的二叉树。从根节点到叶子节点的路径就表示一个决策。每个结点都有一个数字f(node)表示该结点的找到钥匙的期望寻找次数。当前节点的期望寻找次数依赖于它的两个儿子(分别对应去家里找和去学校找的期望寻找次数)中的期望寻找次数较小者。按照这个方法,暴力枚举整个满二叉树上的决策,发现最终得到的决策路径和贪心法找大的决策路径是一致的。

期望寻找次数为:3.1857095316916766

f(p) 函数表示钥匙在家时,期望寻找次数。这个函数表达式为
$$f(p)=min\{1+(1-pa)f(\frac{p-pa} { 1 - pa}),1+(1-b+pb)f(\frac{p}{1-b+pb})\}$$

根据贪心法(若不是此问题的具体情境,很难看出上式可以转化为条件函数)可以化简此式:
贪心条件为 $pa\circ(1-p)b$,也就是 $p\circ \frac{b}{a+b}$
这个公式等价于

$$f(p)= \begin{cases} 1+(1-pa)f(\frac{p-pa} { 1 - pa}) when p\gt\frac{b}{a+b} \\ 1+(1-b+pb)f(\frac{p}{1-b+pb}) when p\le\frac{b}{a+b}\\ \end{cases}$$

其中,a、b为常量,p取值范围(0,1)
这个解析式是否能够进一步化简呢?

a = 0.8  # 在家找到的概率
b = 0.4  # 在学校找到的概率


def solve(p, c):
    # 钥匙在家的概率为p,返回最优决策、期望找到钥匙所花费的步数
    if c == 0:
        return max(1 / a, 1 / b)  # 如果最后没有找到
    if p > b / (a + b):
        step = solve(p * (1 - a) / (1 - p * a), c - 1)
        ifhome = 1 + step * (1 - p * a)  # 如果去家里找,期望找到的步数
        return ifhome
    else:
        step = solve(p / (1 - (1 - p) * b), c - 1)
        ifschool = 1 + step * (1 - (1 - p) * b)
        # 选取两个儿子中期望步数较小者
        return ifschool


import pylab as plt
import numpy as np
print(solve(0.3, 200))
xs = np.linspace(0, 1, 1000)
ps = [solve(i, 200) for i in xs]
plt.plot(xs, ps)
plt.xlabel("p")
plt.ylabel("step")
print(b/(a+b))
plt.plot([b/(a+b)] * 100, np.linspace(0, max(ps), 100), c='r')
plt.show()

使用tensorflow求解迭代形式的函数方程

import tensorflow as tf
import pylab as plt
import numpy as np
import os
a = 0.8
b = 0.4
c = 1000

loss = tf.constant(0.0)
xs = np.linspace(0, 1, c)
fp = tf.Variable(tf.random_uniform((c,)), dtype=tf.float32)
if not os.path.exists("img"):
    os.mkdir('img')
for i in range(c):
    p = xs[i]
    if p > b / (a + b):
        next_p = (p - p * a) / (1 - p * a)
        next_ind = int(round(next_p * c))
        next_ind = min(c - 1, next_ind)
        y = 1 + (1 - p * a) * fp[next_ind]
    else:
        next_p = p / (1 - b + p * a)
        next_ind = int(round(next_p * c))
        next_ind = min(c - 1, next_ind)
        y = 1 + (1 - b + p * b) * fp[next_ind]
    loss = loss + tf.abs(y - fp[i])
train_op = tf.train.AdamOptimizer(0.01).minimize(loss)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(100000):
        _, lo = sess.run([train_op, loss])
        if i % 1000 == 0:
            if i % 5000 == 0:
                plt.close()
                plt.figure()
            print(i, lo)
            plt.plot(xs, sess.run(fp))
            plt.savefig("img/%s.jpg" % i)

转载于:https://www.cnblogs.com/weiyinfu/p/10227020.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值