今天看朋友发了一个老问题,一道很有意思的推理题:(转载请指明出于breaksoftware的csdn博客)

小明和小强都是张老师的学生,张老师的生日是M月N日,2人都知道张老师的生日是下列10组中的一天:

3月4日 3月5日 3月8日
        6月4日 6月7日
        9月1日 9月5日
        12月1日 12月2日 12月8日
        张老师将M值告诉了小明,将N值告诉了小强,张老师问他们知道他的生日是哪一天吗?
        小明说:如果我不知道的话,小强肯定不知道
        小强说:本来我也不知道,但是现在我知道了
        小明说:哦,那我也知道了
        据上面信息,推断出张老师的生日是哪一天?

这个逻辑题,如何用程序实现?其实这是一个建模过程,我们需要用专业的术语重新描述这个逻辑。

这个问题数据只有2个:月数和天数。逻辑是参杂2个人角度看问题的3句话。我们分析这个问题时,首先要保持第三者的视角,逐个从其他两个视角去分析这个问题。然后就是建立模型,我们看这样的数据有个特征:{Key,Value}键值对。但是可以看出这是个MultiMap,即一个键可以对应多个值。

我们沿着这个思路走.可以发现,站在小明的角度,我们可以将数据建立成一个MultiMap。他眼中的数据使用月数M为键,天数N为值。以后我们称下表为“小明表”。

可以站在小强的角度,我们将数据建立成一个新的MultiMap。他眼中的数据使用天数N为键,月数M为值。以后我们称下标为“小强表”。

我们再回到第三者的角度,可以得出,这两张表对于小明和小强都是可见的。

我们将小明和小强的对话,一条一条转换为约束条件。

1 小明说:如果我不知道的话,小强肯定不知道

小明是看了“小强表”之后得出以上结论。这句话意味着:他所知的M值在“小强表”中不存在Key Value唯一对应关系。即12月2日和6月7日,这两个月份12和6都不是老师的生日月数。因为如果是M是12或6,小明在不知道N的情况下,无法给定如此“拽”的回答。于是逐步排除出一下结果(红色代表排除的选项)

2 小强说:本来我也不知道,但是现在我知道了

小强在看到上图后,得出上面结论。这个说明,小强知道的N在上表中是Key Value唯一对应关系。于是得出

因为小强知道N是多少,所以剩下的选项中,他知道正确答案了。只是我们还不知道。我们期待小明的话。

3 小明说:哦,那我也知道了

对于小明,他和我们一样,可以看到上图。于是他知道N的值只可能是1、4、8。于是修改“小明表”为

由于此时小明已经知道了答案。可以见得M值在上表中是Key Value唯一对应关系。于是我们可以排除3和12。得出

此时有两个答案。我们此时结合筛选后的“小强表”

此时,我们可以说6月4日在“小强表”中已被排除,所以我们选择9月1日。或者我们从这个两个表中找到了唯一的共同选项,从而得知是9月1日。

草编了一下代码

// ACM.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <list>
/*
小明和小强都是张老师的学生,张老师的生日是M月N日,
2人都知道张老师的生日是下列10组中的一天,
张老师将M值告诉了小明,将N值告诉了小强,
张老师问他们知道他的生日是哪一天吗?
3月4日 3月5日 3月8日
6月4日 6月7日
9月1日 9月5日
12月1日 12月2日 12月8日
小明说:如果我不知道的话,小强肯定不知道
小强说:本来我也不知道,但是现在我知道了
小明说:哦,那我也知道了
据上面信息,推断出张老师的生日是哪一天?
*/
struct stBirthday{int nMonth;int nDay;bool bMaybe;bool bMaybeSecond;bool bMaybeThird;
};static stBirthday g_BirthdayArray[] = {{3,4,false,false,true},{3,5,false,false,true},{3,8,false,false,true},{6,4,false,false,true},{6,7,false,false,true},{9,1,false,false,true},{9,5,false,false,true},{12,1,false,false,true},{12,2,false,false,true},{12,8,false,false,true},
};int g_nArrayCount = sizeof(g_BirthdayArray)/sizeof(stBirthday);typedef std::list<stBirthday> ListBirthday;
typedef ListBirthday::iterator ListBirthdayIter;void XiaoMingFirst(ListBirthday& listBirthday)
{// 小明知道月数后,说:如果我不知道,小强肯定也不知道// 这意味着小明看了他所知道月数里的每个天数在其他月数里都能找到// 于是天数具有唯一性的选项是“不可能”的for ( ListBirthdayIter it = listBirthday.begin(); it != listBirthday.end(); it++ ) {if ( it->bMaybe ) {// 该值可能在之后的逻辑中提前被设置,所以不用比较// 这个日期是存在可能的continue;}for ( ListBirthdayIter iter = it; iter != listBirthday.end(); iter++){if ( iter == it ) {// 不和自身比较continue;}if ( it->nDay == iter->nDay ) {// 第一个答案的提炼的思想就是:// 小明看了他所知道月数里的每个天数在其他月数里都能找到// 所以,没有小明的答案,小强肯定不知道确切的几月几日// 于是,我们将有天数有重复的答案认定为可能的选项it->bMaybe = iter->bMaybe = true;}}}for ( ListBirthdayIter it = listBirthday.begin(); it != listBirthday.end(); it++){if ( it->bMaybe ) {continue;}// 经过上轮处理,需要将该月里可能同时存在“可能”和“不可能”的选项的可能性都设置为“不可能”// 因为小明看了他所知道月数里的每个日数在其他月数里“都”能找到,我们要配合“都”这个必要条件for ( ListBirthdayIter iter = listBirthday.begin(); iter != listBirthday.end(); iter++){if ( it->nMonth == iter->nMonth ) {iter->bMaybe = false;}}}
}void XiaoQiangFirst(ListBirthday& listBirthday)
{// 小强分析了小明回答后,回答:本来我也不知道,但是现在我知道了// 这意味着小明的答案给小强提供了月数信息// 因为小明的回答让他在待选择的多个结果中排除了其他可能性,只有一个选择// 于是编码的思路就是:// 1 在已经“不可能”的月数中,寻找其对应的天数在“可能”的月中是否有对应关系// 或者// 2 在已经“可能”的月数中,寻找其对应的天数在“不可能”的月中是否有对应关系// 以下编码选择1思路实现for ( ListBirthdayIter it = listBirthday.begin(); it != listBirthday.end(); it++ ) {if ( it->bMaybe ) {// 寻找“不可能”的月数,于是“可能”的月数不作为可选条件continue;}for ( ListBirthdayIter iter = listBirthday.begin(); iter != listBirthday.end(); iter++){if ( false == iter->bMaybe ){// 在找到一个“不可能”的月数情况下,寻找“可能”的月数,以作下步筛选continue;}if ( it->nDay == iter->nDay ) {// 存在对应关系,则该“可能”日期经过第二轮筛选,还是“可能”的iter->bMaybeSecond = true;}}}
}void XiaoMingSecond(ListBirthday& listBirthday)
{// 小明在听到小强的回答后,说:哦,那我也知道了。// 这意味着小强的答案已经为小明提供了天数信息// 在可能众多的选项中,小明却知道了答案,// 证明信息经过小强筛选过后,小明所知道的月数中,只有一个天数答案for ( ListBirthdayIter it = listBirthday.begin(); it != listBirthday.end(); it++ ) {if ( false == it->bMaybeSecond ) {it->bMaybeThird = false;continue;}for ( ListBirthdayIter iter = it; iter != listBirthday.end(); iter++){if ( iter == it ) {// 不和自身比较continue;}if ( false == iter->bMaybeSecond || false == iter->bMaybeThird ) {// 不满足条件的不做比较continue;}if ( it->nMonth == iter->nMonth ) {// 经过两轮筛选,如果有两个选项是同一个月数的// 则可以认为该数月的所有选项都是“不可能”for ( ListBirthdayIter iterIn = it; iterIn != listBirthday.end(); iterIn++){if ( it->nMonth == iterIn->nMonth ) {iterIn->bMaybeThird = false;}}}}}
}void TestBirthday()
{ListBirthday listBirthday;for ( int n = 0; n < g_nArrayCount; n++ ) {listBirthday.push_back(g_BirthdayArray[n]);}XiaoMingFirst(listBirthday);printf("The First Result:\n");for ( ListBirthdayIter it = listBirthday.begin(); it != listBirthday.end(); it++ ) {if ( it->bMaybe ){printf("Month:%d Day:%d\n", it->nMonth, it->nDay);}            }XiaoQiangFirst(listBirthday);printf("The Second Result:\n");for ( ListBirthdayIter it = listBirthday.begin(); it != listBirthday.end(); it++ ) {if ( it->bMaybeSecond ){printf("Month:%d Day:%d\n", it->nMonth, it->nDay);}           }XiaoMingSecond(listBirthday);printf("The Third Result:\n");for ( ListBirthdayIter it = listBirthday.begin(); it != listBirthday.end(); it++ ) {if ( it->bMaybeThird ){printf("Month:%d Day:%d\n", it->nMonth, it->nDay);}         }
}int _tmain(int argc, _TCHAR* argv[])
{TestBirthday();return 0;
}

使用程序解决一道逻辑推理题相关推荐

  1. java逻辑编程题_用Java编程解决一道逻辑推理题

    package mytest; import java.util.Scanner; public class Test14 { /** * 竞赛结果表明,他们都说对了一半,说错了一半,并且无并列名次, ...

  2. python考试编程题九道_一道逻辑推理题的程序实现(纯属娱乐)

    一份逻辑推理题的程序求解(纯属自娱自乐) 闲来无聊,看到QQ空间上转载了一份变态推理题的,至少表示我看了十多分钟无处下手,认识的人中有大神居然真的做出来了...我不知道他是们那么做的,不过作为编程爱好 ...

  3. 一道逻辑推理题的程序实现(纯属娱乐)

    一份逻辑推理题的程序求解(纯属自娱自乐) 闲来无聊,看到 QQ空间上转载了一份变态推理题的,至少表示我看了十多分钟无处下手,认识的人中有大神居然真的做出来了...我不知道他是们那么做的,不过作为编程爱 ...

  4. 用程序消除一道概率题的二义性

      无意在维基看到了一个关于概率悖论的讨论Boy or Girl paradox.有争议的的题目如下:   史密斯先生有两个孩子,至少其中之一是男孩,请问两个孩子都是男孩的可能性有多大?   原文如下 ...

  5. c语言中有12个球,数学老师做不出来的一道逻辑推理题

    同志们 那个球不一定轻啊 正确的是 平分三份 取两分称 if(平) ......在未称过的4球中取两个放左边 和标准的球称(称过的球一定标准) ......if(平) ............在两次都 ...

  6. java之黑帽子逻辑题_一道逻辑推理题有2种帽子,黑的和

    2006-10-08 我是骨招死灵,现有2个帽子,一个 第一个,因为可以给骷髅和骷髅支配及精灵等等都加一技能点(包括必修的尸体爆炸和伤害加深也加了一技能点,而另一个骷髅支配+3的就差多了. 附加个骨招 ...

  7. 用编程解决 公务员考试 中的逻辑推理题

    一.背景 朋友这几天在准备公务员考试,闲聊之中,给我传来一道题,是一道逻辑推理题,问我答案为何? 让我这个工作好几年的老油条再做这种题,真的伤脑筋,我说:"干脆我用编程做做看吧", ...

  8. 微软的一道经典逻辑推理题:小明和小强都是张老师的学生,张老师的生日是M月N日

    微软的一道经典逻辑推理题:小明和小强都是张老师的学生,张老师的生日是M月N日 分类: 天下杂侃 2008-08-07 23:37 17495人阅读 评论(21) 收藏 举报 题目是这样的: 小明和小强 ...

  9. 微软的一道经典逻辑推理题 小明和小强都是张老师的学生,张老师的生日是M月N日

    微软的一道经典逻辑推理题:小明和小强都是张老师的学生,张老师的生日是M月N日 分类: 天下杂侃 2008-08-07 23:37 17495人阅读 评论(21)收藏 举报 题目是这样的: 小明和小强都 ...

最新文章

  1. 95页重磅报告:全面预测未来5年趋势
  2. 电路设计中三极管和MOS管做开关用时的区别
  3. PMM (Percona MySQL Monitor) 部署
  4. one order event handling - event filtering
  5. 不同组合方式有四种纸币java_拼凑钱币丶Java教程网-IT开发者们的技术天堂
  6. LAMP基于php模块实现个人博客搭建
  7. 十天学会ASP.Net——(2)
  8. esp8266 micropython oled_micropython(4):使用ESP8266 控制 oled 屏幕,并显示 helloworld 字符...
  9. 基于JavaWeb实现的研究室综合系统
  10. 95-10-055-启动-MetadataCache
  11. __new__()方法的使用和实例化
  12. 腾讯 android 插件,腾讯 Bugly for Xamarin Android 的插件
  13. Linux安装Diamond软件,Diamond软件比对蛋白质数据库
  14. mysql查询字段为null的方法
  15. ensp查看历史配置命令_学习华为ensp基本命令小技巧
  16. ubuntu freeswitch安装
  17. Word 页眉 页脚 出现一条横线删不掉
  18. 澄清server push/websocket/sse的一些概念
  19. 怎么彻底卸载2345软件、怎么屏蔽2345弹窗
  20. c语言随机数 抛硬币,C语言 抛硬币的问题

热门文章

  1. 0基础小白学好JAVA的5个方法
  2. Python:KNN
  3. LabVIEW条形码识别(实战篇—5)
  4. 【camera-radar】相机-毫米波雷达联合标定方案介绍+实现
  5. 四、One-hot和损失函数的应用
  6. 【透明版九宫格背景图片】仅依靠background的几个属性组合搭配出酷炫的透明背景卡片效果→适用于大数据可视化、数据大屏展示页面
  7. 利用lua中的string.gsub来巧妙实现json中字段的正则替换
  8. 3dmax Vray建筑可视化入门学习教程
  9. leetcode-386 字典序排数
  10. linux 文件IO与内存映射:内存映射