Toad趣题:说真话的程序员 & 不说实话的经理

来源:互联网 发布:mac jenkins 启动 编辑:程序博客网 时间:2024/05/22 22:50

原题在这里: http://www.cs.cmu.edu/puzzle/puzzle1.html

FBI包围了诺恩公司的总部。里面总共有n个人。每个人不是工程师就是经理。机密文件已经被销毁,只有经理掌握。现在FBI要分辨他们。只能问i:“j是什么身份”。诺恩中每个人相互都知道身份。工程师只说真话;经理并不总是说真话,而且都足够狡猾,想尽方法迷惑FBI。(出题人是在吐槽经理吗)

1 假如一半以上的人都是工程师,是否有一个策略,用最多n-1次提问找到一位工程师。
2 假如有至少一半的人是经理,是否能找到一位工程师。

3 一旦找到了一个工程师,通过他可以认清其他人的身份。是否可以用更少的询问次数来确认所有人的身份。


第一问,n-1次是一个限制比较苛刻的条件。如果把这个条件放松,不限制询问次数,是有办法的。注意到有一半以上的人说真话,那么问一遍所有人:第i个人是E(工程师)还是M(经理)。肯定有一半以上的人的答案是相同的,这就是i的身份。依次运用这种方式,可以找出所有人的身份。

第一问的解答稍后再看。


第二问,现在经理的人数分庭抗礼,甚至占了上风,如何判断?

为了简化问题,可以把问题特殊化:如果有2个人,a是M,b是E。你是否能找出他们的身份呢?

两种情况:

1)询问某人自己是什么身份,他的回答一定是E。   (他如果是工程师,会如实回答E;如果是M,可能会回答E或M。但是如果他的回答是M,我们就能肯定,他就是M。所以经理要宣传自己是E。)这就好像坏人一定不会说自己是坏人一样。

2)如果询问a,b,对方是什么身份。

a是工程师的话,他如实说对方是M;

b是经理,他一定要说a是狡猾的经理。(否则就等于承认自己经理,注意条件是两人当中要有一个人是经理。)所以,经理为了迷惑我们,他的策略是:说a是M。


如果推广到更多的人,且我们知道工程师和经理是一半对一半。

那么总会有一半的人,任意两两个人互相声称对方是勤劳智慧的E,所以他们形成了半壁江山的团体。

经理的策略必须是:团结所有经理,声称所有的经理都是诚实的是工程师;排斥工程师,说他们是狡猾的经理。

从我们看来,只知道这群人按照身份分成两个人数相同阵营,却无从知晓谁是谁非。


通过上面的分析,也可以总结出:

引理1:如果一群人,任意两两互相说对方是工程师,他们的身份一定是相同的。我们可以把他们看成一个阵营  。

引理2:如果一个人说对方是狡猾的经理,要么其中一个人经理,要么两个人都是经理。我们可以把他们看成不同的阵营。


如果经理数占了上风,并且我们也不知道到底有多少勤劳智慧的工程师:

情形1: {a}是E,{b,c}是M。经理可以通过计划好自己的说辞,让我们判断:a是一1号阵营,b是2号阵营,c是3号阵营。

情形2:如果有6个人,[1,2]是E,[3,4,5,6]是M。经理们可以形成{3,4}、{5,6}两个阵营,或者是{3}  {4,5,6}的阵营

总之,在这些情况下,相同阵营中的身份是一致的,但是我们无法找到工程师阵营。

因此第二问的回答是否定的。


回到第一问。如果有一半以上的人是经理,能否使用n-1次询问找到其中一个工程师。

答案不那么显而易见,因为要求我们去设计某种策略、算法。

策略1:依次问所有人,某个人a是什么身份。如果有n/2次询问,我们仅可以确定他的身份。如果他是经理,就用掉一半的询问。这种方法不可行

策略2:

……


通过盲目的试探很难找到方法,所以需要从题目的条件,以及引申出来的引理来制定策略:

引理3:如果整个过程当中有至少一半的人,说某个人是工程师,那么这个人确实就是工程师。(为什么?)

引理4:如果a承认b是工程师,那么a认可b所有的判断。例如,如果b宣传c是工程师,那么a也认同c是工程师。

引理5:”认同队列“。有m个人,依次是{1,2,3,4……},后一个人说前面的人是工程师。根据引理5,等于所有人都认同1是工程师。


根据引理2:"如果一个人说对方是狡猾的经理,要么其中一个人经理,要么两个人都是经理。"把这两个人排除掉,剩下的人的当中还是保持了有一半的人以上是工程师。这等于缩小了问题的规模。最开始的问题看成是q(n, n-1),排除了两个人以后变成了q(n-2, n-2)。

人员按1到n排序。先把第一个人放到队列的开头。从第二个人开始,询问他队列最后一个人的身份。如果他回答是E,把他加到队列的最后;如果他的回答是M,把他和队列最后的一个人排除掉。当问完最后一个人以后,队列所有人都认同队首的人是工程师。并且队列当中有一半以上的人工程师。所以可以判断队首的人是工程师


第三问


0 0