侧边栏壁纸
博主头像
钱学超博主等级

火星人,1万小时法则的忠实拥趸。技术宅,象棋和羽毛球爱好者,马拉松PB成绩:4小时零8分。坚持认为算法是计算机的灵魂。喜欢解决问题,喜欢手工,喜欢与朋友们聊天喝酒吹牛X。

  • 累计撰写 81 篇文章
  • 累计创建 447 个标签
  • 累计收到 87 条评论
标签搜索

目 录CONTENT

文章目录

关于美女和硬币的博弈问题,重新解释一次,看看有没有说明白。

钱学超
2022-03-22 / 0 评论 / 0 点赞 / 856 阅读 / 1,542 字 / 正在检测是否收录...
  1. 美女和硬币的博弈问题是一个经典的博弈论课题。

  2. 美女和倒霉蛋每人持有一枚硬币,各自决定自己的硬币是正面还是反面,然后一起进行比对。

  3. 如果均为正面,美女给倒霉蛋3元,如果均为反面,美女给倒霉蛋1元;如果一正一反,倒霉蛋给美女2元。

  4. 表面上看,每一种可能性都是1/4,所以每个人的数学期望都是0.也就是不输也不会赢。

  5. 但是,双方均想赢了对方,所以会对自己的出币行为应用一定的策略。下面我们就要对这种策略进行研究。

  6. 美女出正面的概率是m,倒霉蛋出正面的概率是d,那么,倒霉蛋(换成美女也行)的收益的数学期望是:

     
    E = (mxdx3)+((1-m)x(1-d)x1)+((1-m)xdx-2) + (mx(1-3)x-2)
     

  7. 美女要想赢,就得让倒霉蛋输,也就是他的数学期望应该小于0才对。

     
    E<0 => 8md-3m-3d+1 < 0
    也就是:
    m(8d-3)<3d-1
     

    初中数学哈,把 8d-3 右移,不等式的话,就涉及到这个8d-3是正数,还是负数,还是0了。

    毋庸置疑,如果d = 3/8,不等式肯定成立,不用考虑m的取值。反之也是一样,因为m和d是对等的,上面的不等式也可以是:
    d(8m-3)<3m-1
    也就是说,无论是美女选择固定的以3/8的概率出正面(不关心倒霉蛋怎么出),还是倒霉蛋选择以3/8的概率出正面(不关心美女怎么出),上面的不等式都是成立的,也就是倒霉蛋是赔钱的。

    那么,就需要考虑剩下的两种情况,8d-3大于0,以及8d-3小于0两种情况。

    ①. 8d-3 > 0, 则 d>3/8 , 则 m < (3d-1)/(8d-3) ,当d的取值范围是:(3/8,1]的时候,m 是一个随d变化的减函数,d 趋近于3/8时,右侧表达式趋近于无穷大,d等于1的时候,右侧等于2/5。也就是 m < 2/5。 也就是说,m的取值,最大可以是2/5(不含),可以让不等式成立。
    ②. 8d-3 < 0, 则 d<3/8, 则 m > (3d-1)/(8d-3) ,当d的取值是[0,3/8)时,m是一个随d变化的减函数,当d趋近于3/8时,右侧趋近于无穷小,当d等于0时,m > 1/3 ,也就是说,m最小也可以是1/3,可以保证不等式成立。

    综上所述,当 m 的取值范围是 (1/3,2/5)时,无论d的取值范围怎样变化,不等式都是始终成立的。也就是倒霉蛋恒亏钱。

  8. 好的,不知道解释明白了没有。

  9. 为了验证美女和硬币的问题,我写了一段代码,来帮助大家理解。先上代码,大家凑合看一下(jdk17.0)

/**
 * 出手策略,开始投注,需要依据一定的策略,进行投注,是否正面和背面。
 **/
public abstract class BetPolicy {
    // 默认的概率模型是50%,正反面。
    private double _low = 0.0;
    private double _high = 0.5;
    private boolean _lowInclude = false;
    private boolean _highInclude = false;
    // 初始金额 0
    protected long money = 0l;

    protected long wonCnt = 0;
    protected long lostCnt = 0;

    // 当前的硬币是正面吗?
    private boolean myFace = false;

    // 胜利条件的对应关系
    protected Map<String, Integer> _mpWinMap = new HashMap<>();
    // 赢得比赛的条件。
    public abstract void initPolicy();

    BetPolicy() {
        initPolicy();
    }
    // 设置概率上下限
    public void setProbBound(double low, double high, boolean lowInclude, boolean highInclude) {
        _low = low;
        _high = high;
        _lowInclude = lowInclude;
        _highInclude = highInclude;
    }
    // 概率边界
    public String getBounds() {
        String start = _lowInclude ? "[" : "(";
        String end = _highInclude ? "]" : ")";
        return start + _low + " , " + _high + end;
    }

    // 是否正面
    public boolean coinFace() {
        double one = Math.random();
        myFace = false;
        // 符合指定概率模型的时候,返回正面。默认情况,按照50%的概率选择正反面
        if ((_lowInclude ? one >= _low : one > _low) && (_highInclude ? one <= _high : one < _high)) {
            myFace = true;
        }
        return myFace;
    }

    // 赢了,钱增加,赢的次数增加。输了,钱减少,输的次数增加。
    public void bet(boolean target) {
        var ret = _mpWinMap.get("" + myFace + "_" + target);
        if (ret > 0) {
            wonCnt++;
        } else {
            lostCnt++;
        }
        money += ret;
    }

    /// 说出结果
    public void say() {
        System.out.println("我赢了" + wonCnt + "次,现在共有:" + money + "元钱,赢的概率是:" + (wonCnt * 1.0 / (wonCnt + lostCnt)) + " 平均每次赢 " + (money * 1.0 / (wonCnt + lostCnt)) + "元");
    }
}

/**
 * 美女的打赌策略
 */
public class Beauty extends BetPolicy {

    @Override
    public void initPolicy() {
        // 美女的正面策略
        setProbBound(0, 3 / 8.0,true,true);
        _mpWinMap.clear();
        _mpWinMap.put(true + "_" + true, -3);
        _mpWinMap.put(true + "_" + false, 2);
        _mpWinMap.put(false + "_" + true, 2);
        _mpWinMap.put(false + "_" + false, -1);
    }
}

/**
 * 倒霉蛋的打赌策略
 * */
public class Victim extends BetPolicy {

    @Override
    public void initPolicy() {
        _mpWinMap.clear();
        _mpWinMap.put(true + "_" + true, 3);
        _mpWinMap.put(true + "_" + false, -2);
        _mpWinMap.put(false + "_" + true, -2);
        _mpWinMap.put(false + "_" + false, 1);
    }

}

// 美女和硬币,运行100次,以0.01的步进,检索一下倒霉蛋有没有破局的可能性。当然,各位可以发挥一下,看看什么情况下倒霉蛋赔钱最多,什么情况下美女赢钱最少。
public class BeautyAndCoin {
    // 总共运行的次数
    static final long totalCnt = 10000000;
    // 程序入口
    public static void main(String[] args) {
        for (double bm = 0; bm < 1; bm += 0.01) {
            oneBet(0, bm);
        }
        System.out.println("运行结束。");
    }
    // 来一局
    public static void oneBet(double low, double high) {
        var beauty = new Beauty();
        var victim = new Victim();
        victim.setProbBound(low, high, true, true);
        for (long i = 0; i < totalCnt; i++) {
            var victimRet = victim.coinFace();
            var beautyRet = beauty.coinFace();
            beauty.bet(victimRet);
            victim.bet(beautyRet);
        }
        System.out.println("美女的策略是:" + beauty.getBounds());
        System.out.println("倒霉蛋的策略是:" + victim.getBounds());
        System.out.println("美女说:");
        beauty.say();
    }

}

0

评论区