用编程的思路模拟解决脑筋急转弯问题

量化策略岗面试真题解析:从概率题到编程实现(实战指南) 本文深入解析量化策略岗面试中的经典概率题,如“麦乐鸡问题”和“赌徒破产”,揭示其背后考察的数学建模、逻辑推理及编程实现能力。通过Python代码实战,演示如何将概率理论与动态规划、蒙特卡洛模拟相结合,应用于风险管理、订单执行等核心量化交易场景,为求职者提供从解题到实战的完整指南。 阅读详情

前些日子看了可汗学院的这个关于诚实人和说谎者的脑筋急转弯问题,我觉得如果能用程序来模拟,那一定很有趣。

Flash Animation

这个题目是这样的,有两扇门,一扇通往天堂,一扇通往地狱,你要做出选择打开那扇门。门口各有一个人,他们都知道门后面的情况,其中一个总是说实话,而另一个总是撒谎。你可以问他们问题。要怎样问问题,才能做出正确的选择?

在揭开答案之前,我们先看看我是如何用JavaScript来模拟这个问题的。

function Game() {
  var destinations = ["Heaven", "Hell"];
  var gates = {}, persons = {};

  function Gate() {
    var val = undefined;
    return {
      value: function(_) {
        if (!arguments.length) {
          return val;
        }
        val = _;
      },
      open: function() {
        if (val === destinations[0]) {
          console.log("Happy Ending!");
        } else {
          console.log("You Die!");
        }
      }
    }
  }

  function Behavior(isLier) {
    var tellTruth = function(info) {
      return info;
    };
    var tellLie = function(info) {
      var index = destinations.indexOf(info);
      if (index === 0) {
        return destinations[1];
      } else {
        return destinations[0];
      }
    };
    return isLier ? tellLie : tellTruth;
  }

  function Person(gate, behavior) {
    return {
      ask: function() {
        return behavior.call(this, gate.value());
      }
    }
  }

  function Init() {
    gates.A = Gate();
    gates.B = Gate();

    if (Math.random() > 0.5) {
      gates.A.value(destinations[0]);
      gates.B.value(destinations[1]);
    } else {
      gates.A.value(destinations[1]);
      gates.B.value(destinations[0]);
    }

    if (Math.random() > 0.5) {
      persons.A = Person(gates.A, Behavior(true));
      persons.B = Person(gates.B, Behavior(false));
    } else {
      persons.A = Person(gates.A, Behavior(false));
      persons.B = Person(gates.B, Behavior(true));
    }
  }

  Init();

  return {
    open: function(gateName) {
      gates[gateName].open();
    },
    ask: function(personName) {
      return persons[personName].ask();
    }
  }
}


程序主要有以下方法:

  • Gate

    Gate方法负责创建们,每扇门提供两个方法, value方法负责读写们的内容,open方法检查开门后的结果。如果是天堂,则打印“Happy Ending”, 游戏成功;如果是地狱则打印“You Die”,游戏失败。

  • Behavior

    Behavior是对说谎和说实话这两种行为的抽象。返回两个不同的方法,说谎的行为总是返回和原本信息不一致的信息,而说实话则返回原本的信息。

  • Person

    Person方法负责创建人,并关联人所在的门,指定人的行为。

  • Init

    Init方法随机初始化门和人

  • Game

    Game方法是最外层的闭包,他暴露出游戏者可以调用的两个方法,问问题和开门。因为Person和Gate都在闭包里所以游戏者无法获得任何相关的信息,只能通过ask方法来问问题。

调用以下方法来运行游戏:

var g = Game();
console.log(g.ask("A"));
console.log(g.ask("B"));


因为A和B有一个人说谎,所以条用的结果是他们都说自己后面的门是“天堂”,或者都说是“地狱”。

于是无论打开A还是B,游戏者都只有50%的概率获胜。

好了,现在是揭晓答案的时候了,这道题,游戏者需要这样问,“如果问另外一个人你后面的门后是什么,他会怎么说?”会有两种情况:

  • 问诚实人说谎者怎么回答他后面的门是什么,因为说谎者会说谎话,而诚实的人会原封不动的返回这个回答,所以提问者会得到错误的答案

  • 问说谎者诚实人怎么回答他后面的门是什么,因为说谎者会说谎话,他会把诚实人的正确答案变成谎话回答,所以答案还是错误的。

那么我们要怎样修改我们的程序呢?

其实改动很简单,首先要增强Person方法

function Person(gate, behavior) {
    return {
      ask: function(aGate) {
        if(!aGate) {
          return behavior.call(this, gate.value());
        } else {
          return behavior.call(this, aGate.value());
        }
      },
      askBy: function(accordingTo) {
        return behavior.call(this, accordingTo.ask(gate));
      }
    }
  }


在Person方法中增强ask方法,暴露门的信息,也就是说每个人不但知道自己的门后的东西是什么,也能回答另一扇门后是什么。所以通过参数传递门的引用。这里我们可以看出,在前一版中假定人和门之间的耦合关系是不成立的,其实完全应该可以帮人和门解耦。

另外增加了askBy方法,这个方法会去问另一个人,我给你的门后面的信息,然后用自己的行为返回出去。

除了扩展Person,我们还要扩展Game返回的对象,增加新的提问方式:

  return {
    open: function(gateName) {
      gates[gateName].open();
    },
    ask: function(personName) {
      return persons[personName].ask();
    },
    askBy : function(personName, byName) {
      return persons[personName].askBy(persons[byName]);
    }
  }


这样,新暴露的askBy方法就可以正确的找到错误的门了(听上去很绕口)

增强后的代码如下:

function Game() {
  var destinations = ["Heaven", "Hell"];
  var gates = {}, persons = {};

  function Gate() {
    var val = undefined;
    return {
      value: function(_) {
        if (!arguments.length) {
          return val;
        }
        val = _;
      },
      open: function() {
        if (val === destinations[0]) {
          console.log("Happy Ending!");
        } else {
          console.log("You Die!");
        }
      }
    }
  }

  function Behavior(isLier) {
    var tellTruth = function(info) {
      return info;
    };
    var tellLie = function(info) {
      var index = destinations.indexOf(info);
      if (index === 0) {
        return destinations[1];
      } else {
        return destinations[0];
      }
    };
    return isLier ? tellLie : tellTruth;
  }

  function Person(gate, behavior) {
    return {
      ask: function(aGate) {
        if(!aGate) {
          return behavior.call(this, gate.value());
        } else {
          return behavior.call(this, aGate.value());
        }
      },
      askBy: function(accordingTo) {
        return behavior.call(this, accordingTo.ask(gate));
      }
    }
  }

  function Init() {
    gates.A = Gate();
    gates.B = Gate();

    if (Math.random() > 0.5) {
      gates.A.value(destinations[0]);
      gates.B.value(destinations[1]);
    } else {
      gates.A.value(destinations[1]);
      gates.B.value(destinations[0]);
    }

    if (Math.random() > 0.5) {
      persons.A = Person(gates.A, Behavior(true));
      persons.B = Person(gates.B, Behavior(false));
    } else {
      persons.A = Person(gates.A, Behavior(false));
      persons.B = Person(gates.B, Behavior(true));
    }
  }

  Init();

  return {
    open: function(gateName) {
      gates[gateName].open();
    },
    ask: function(personName) {
      return persons[personName].ask();
    },
    askBy : function(personName, byName) {
      return persons[personName].askBy(persons[byName]);
    }
  }
}


调用以下代码来问新的问题:

var g = Game();
console.log(g.askBy("A","B"));
console.log(g.askBy("B","A"));


游戏者只要打开和回答不一致的门就可以马上升入天堂!

通过这个例子,我们发现对Behavior的抽象对进一步问题的扩展起到了很大的帮助。这也展现了基于Function编程的灵活性,不难想象,如果我们把说谎者和诚实人按照面向对象的方式来构造,而不是把说谎还是说真话作为行为注入到一般的人上,对新的问题的扩展将会比较困难。

醉汉登机问题:用Python模拟10000次实验验证概率结果 本文通过Python编程模拟经典的‘醉汉登机’概率问题,运行10000次蒙特卡洛实验验证了反直觉的结论:无论飞机上有多少乘客,最后一人坐到自己座位的概率恒为1/2。文章详细拆解了问题规则,提供了完整的模拟代码、结果分析和可视化,并探讨了代码优化与问题变体,展示了计算模拟在验证概率理论中的强大应用。 阅读详情

相关推荐

【Py/Java/C++三种语言OD独家2024D卷真题】20天拿下华为OD笔试之【贪心/脑筋急转弯】2024D-环中最长子串【欧弟算法】全网注释最详细分类最全的华为OD真题题解

有LeetCode算法/华为OD考试扣扣交流群可加可上全网独家的练习华子OD、大厂真题绿色聊天软件戳od1441了解算法冲刺训练(备注【优快云】否则不通过)

weixin_48157259的博客 1964

PTA 01背包

题目 事情是这样的,jzk要去爬山,但是他的包容量有限,可是他需要非常多的能量,要不然就很容易饿。 第一行给出jzk准备爬几次山。 每次爬山都会带新的包(因为jzk每用一个包都会被zwg抢过去),和准备新的食物(因为每次剩下来的都被zwg吃了)。 下一行给你这一次食物的数目n,和背包容量k, 接下来的一行给出n个食物的能量,再一行给出n个食物的大小(占背包的容量)。 请帮助jzk计算他最多可以带多少能量的食物去爬山。输出可以携带食物的最大能量和。 (n,m<1000) 能量和食物均小于40000

QYQHxyh的博客 938

Android自带的循环器视图RecyclerView的代码例子

Android自带的循环器视图RecyclerView的代码例子。用于演示RecyclerView在列表展示方面的用法,包括三个布局管理:线性布局管理器LinearLayoutManager、网格布局管理器GridLayoutManager、瀑布流网格布局管理器StaggeredGridLayoutManager

八大排序之插入排序

插入排序 要求:现在有ABCDE五个盒子,现在需要把它们按照从小到大的排序 插入排序算法思路: 第一轮:从B开始往前比较,如果B大于A,则直接下一轮,反之,交换AB 第二轮:从C开始往前比较,如果C大于B,直接下一轮,不用再去比较C,A的大小,因为如果C大于B,则C一定大于A(因为B大于A);如果C小于B,那么首先用一个变量K把C的值先保存起来,然后再把B的值赋给C;如果C还小于A,那就将A的值赋给B,最后把K值赋给A,如果C大于A,那就将K值赋给B; 第三轮:… … 如果有N个数,那么就需要N-1轮,因

weixin_43646100的博客 376

企业AI Agent审计与合规:从日志留存到网络联动的完整落地指南

审计日志是企业安全与合规体系的基石,尤其在AI Agent大规模接入业务后,如何完整记录其行为链成为新的挑战。从日志留存180天到PCI DSS合规要求,审计体系需要覆盖会话、推理、工具调用、数据访问等关键环节,并结合不可篡改的存储设计,确保证据链可信。同时,借鉴上网行为管理设备对应用行为控制审计的思路,以及Kismet被动监测网络流量的方法论,将网络侧审计与应用侧日志交叉验证,能有效发现越权和异常行为。本文从日志采集、全链路追踪、基线预警到多租户隔离,系统梳理了AI Agent审计与合规落地的关键路径,帮

weixin_32234493的博客 271

山东大学软件测试实验2——系统功能测试

​ 给出一个被测试的 Web 应用系统(SUT)。http://211.87.232.162:8080/注:友情链接不用延伸测试。针对被测试的 Web 应用系统进行功能测试,发现其存在的缺陷。 ​

m0_74033391的博客 2410

昌航程序设计竞赛初赛(周五晚19点)

昌航程序设计竞赛初赛(周五晚19点) 7-4 强者为王 (20分) 对抗与比赛是我们进步的动力,加油,奥利给! 能力大于旁边两个人(如果只有一个大于那一个即可)的人我们把它尊之为强者! 这是一个强者为王的世界,那么我们要找到所有强者,并且对他们的能力进行平方强化从而保护这个世界 输入格式: 以空格为分割的10个数字分别代表他们的能力,题目保证没有人能力相同且最大的能力值为9 输出格式: 输出强者的...

小明同学的博客 2015

无监督低照度增强实战:用ZeroDCE和SCI拯救你的夜间照片(附PyTorch代码)

本文深入探讨了无监督低照度图像增强技术,重点解析了ZeroDCE和SCI两大代表性模型的核心原理与实战应用。通过对比分析两者的技术路径、网络结构及性能特点,并附上详细的PyTorch代码实现,旨在帮助读者掌握无需配对数据即可有效提升夜间照片画质的深度学习解决方案。

git9versioner的博客 490

JavaWeb测试:JSP

out对象是javax.servlet.jsp.JspWriter类的实例对象,它的作用与ServletResponse.getWriter()方法返回的PrintWriter对象非常相似,都是用来向客户端发送文本形式的实体内容。答案说明 :<jsp:forward>动作元素可以将当前请求转发到其他Web资源(HTML页面、JSP页面和Servlet等),执行请求转发之后,当前页面将不再执行,而是执行该元素指定的目标页面。在页面中引用标签库后,就可以通过前缀来引用标签库中的标签。

weixin_57242411的博客 730

DDR5内存设计实战:如何通过CA_ODT引脚优化信号完整性(附配置示例)

本文深入探讨DDR5内存设计中CA_ODT引脚的配置与优化策略,通过Group A/Group B分组控制提升信号完整性。详细解析了ODT机制、PCB布局要点及寄存器配置方法,并附实战案例与配置示例,帮助工程师解决高速信号传输中的反射问题,确保DDR5系统稳定运行。

weixin_29202213的博客 400

麒麟V10系统下CoreDump文件自动归档与快速定位指南(附coredumpctl实战)

本文详细介绍了在麒麟V10操作系统下,如何利用systemd-coredump机制和coredumpctl工具实现CoreDump文件的自动化管理与高效调试。内容涵盖从系统架构解析、自动化配置策略,到使用coredumpctl进行快速查询、过滤与深度分析的实战指南,旨在帮助运维人员和开发者快速定位系统崩溃的根本原因,提升问题排查效率。

gg901的博客 223

LeetCode 双周赛 98,脑筋急转弯转不过来!

大家好,我是小彭。昨晚是 LeetCode 第 98 场双周赛,你参加了吗?这场周赛需要脑筋急转弯,转不过来 Medium 就会变成 Hard,转得过来就变成 Easy。

pengxurui的博客 600

在linux上本地大模型部署与推理

您的Python脚本(客户端)可能在您的个人电脑上,而模型服务(服务器)在远程Linux服务器上。如果您的服务器有强大的NVIDIA GPU,并且您对性能有更高的要求(例如需要高吞吐量),vLLM是更好的选择。这种方式无需向公网暴露服务器端口,而是通过加密的SSH通道将服务器的端口“映射”到您的本地电脑上。我们将启动一个API服务器,它会加载您指定的模型,并等待您的代码前来调用。如果您直接在SSH窗口运行上面的命令,一旦您关闭窗口,服务就会停止。这是根据您的原始代码修改的版本,适配本地vLLM服务。

frostmelody 全网同名,大家多多关注呀~ 持续分享优质内容! 2058

(题目更新啦)第十六届蓝桥杯模拟赛(第一期)个人题解

蓝桥杯模拟赛第一期。总体来说题目难度适中,也没有用到太多算法知识,题目随题号基本由易到难。在写代码之前还是要先想清楚一些细节,不然写代码的时候很可能就会漏掉那一丢丢,最后导致重大事故(bushi),尤其是填空题还有就是考场上的每一分钟都很重要,还是要好好检查代码的(不要太提前交卷!),写一遍就过but没有考虑全面的时候很多!最好是全做完再来仔细看遍题目,想下代码有没有完整实现要求,再举出一些极端情况/一般情况的样例进行调试(比如T10)这是一个全新的开始,平时还是要多做题,找灵感。

weixin_66385155的博客 3924

攻防世界 Crypto 新手练习区 1-12 全详解

本篇是攻防世界 Crypto 新手练习区的全解

闵行小鱼塘 3736

S7-1200 PLC PID功能 | 调节PID参数

S7-1200 PLC PID功能 | 调节PID参数

Robot_PLC_HMI_Automation 1万+

[思维] aw3773. 兔子跳(贪心+模拟+脑筋急转弯)

文章目录1. 题目来源2. 题目解析 1. 题目来源 链接:3773. 兔子跳 2. 题目解析 脑筋急转弯的失败…想着每次用最不超过 x 位置的数跳过去,殊不知直接超过 x 也是可以的。例如,3 4 5, x=12,直接 5 5 5 就行了,而不是 5 5 到 10,再来两次…,伞兵了。 思路: 1 步跳到,元素相同即可。 不能一步跳到,则只用关心最大值。 当最大值>x,则 2 步直接到,等腰三角形即可。 当最大值<x,则最后两步构成等腰三角形,等价于上取整。 时间复杂度:O(n)

Y-puyu 的博客 250

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Codeforces Round #747 (Div. 2) A.B

A.Consecutive Sum Riddle **题目大意:**给定整数nnn,求一个(l,r)(l,r)(l,r)使得∑i=lri=n\sum^{r}_{i = l}i = n∑i=lr​i=n。 思路:脑筋急转弯。看看数据范围就知道了对于输入的nnn,令l=1−n, r=nl = 1 - n,\ r = nl=1−n, r=n即可。 #include <bits/stdc++.h> #define int long long using namespace std;

HeartFireY的博客 352

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

双周赛104(模拟、脑经急转弯、贡献法)

题目要求我们选择每一行的最大值,并将其删除,同时在删除的所有数字中找到最大的一个数字并将其加到分数中。a 作为最小值,中间的 b 和 c 可选可不选,一共有 2^2 种方案,所以 a 的贡献是。b 作为最小值,中间的 c 可选可不选,一共有 2^ 1种方案,所以 b 的贡献是。,nm分别表示矩阵的行数和列数,对于每一行,使用sort函数进行排序,时间复杂度为。把「乘 2」分配给多个数,不如只分配给一个数,这样更有可能得到更大的答案。c 作为最小值,一共有 2^0 种方案,所以 c 的贡献是。

qq_42958831的博客 653

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

第二届『Citric杯』NOIP提高组模拟赛

一道防AK的好题     不得不吐槽这个题目背景和算法。这就是一脑筋急转弯啊。 Code program hard; CONST FileName='hard'; var n,i,tot:longint; x,a,b,c,ans:array[1..500000] of int64; left,right:int64; function calc(a,b,c:int64...

weixin_30621711的博客 186

leetcode:521. 最长特殊序列 Ⅰ

这是一道脑筋急转弯 这种easy的题如果想不出 就一定有非常简单的解法。。。 src: class Solution: def findLUSlength(self, a: str, b: str) -> int: # 才100很小 # 直接模拟就好了 # 独有的最长子序列(不用连续) # 我擦!不相等的长的本身一定不是对面的子序列 return max(len(a), len(b)) if a != b els.

小楼一夜听春雨 270

C++牛客周赛题目分享(2)小红叕战小紫,小红的数组移动,小红的素数合并,小红的子序列求和

哈喽大家好喔,今天来给大家带来牛客周赛42部分题目的题解,无论你是小白,还是大牛,你一定都是能看懂的,希望对大家有所帮助,也欢迎大家多多交流,提出不一样但同样很有价值的看法。

2301_81073317的博客 3058

力扣第357场周赛补题

思路:多源bfs+倒序枚举+并查集。

qq_62417282的博客 338

[LeetCode周赛复盘] 第 106 场双周赛20230611

T1 模拟。T2 滑窗。T3 前后缀分解。T4 脑筋急转弯+子集型枚举。

liuliangcan的博客 918

42 场双周赛

1 模拟 2 本来想模仿死锁进程写一个队列的,不过发现太麻烦了。 仔细观察,题目中执行的顺序和到达时间基本是重合的,那么直接遍历执行所有任务,判断当前时间就行。直接模拟 3 最后想出来了,可以利用动态规划,或者之类的思路, 总之,我也不知道该怎么说就是要使得全局最大,那么他的前面几位也一定是最大的。 那么就一位一位的分割,取最大值。 总之,就是把题目划分成更小的规模,利用小规模的解,组成大规模的解。 虽然本题有点脑筋急转弯的嫌疑,但是按照这个思路还是可以解决的。 fine 4 ...

qq_33885275的博客 241
上一篇: 用可视化来讲故事
下一篇: 程序员量子力学-海森堡式BUG
刚是程序员
博客等级 码龄9年 47粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值