名人 (Celebrity)

来源:互联网 发布:黔东南人口数据 编辑:程序博客网 时间:2024/04/27 15:12

问题描述: 在一个聚会上有 n 个人,其中有一个名人,大家都认识他,但他却不认识所有其他人。现在请你只通过询问来宾 x 是不是认识来宾 y 的方式把这个名人找出来。最多只能使用 O(n) 次询问。

当我第一次听到这个问题是,我觉得这题是反直觉的:O(n) 能够做到?随机找一个人,比如说 x,要确定是不是所有人都认识他,就要 O(n) 的时间,确定他是不是不认识所有其他人,也要O(n) 时间。问题是,x 正好是孤独者的概率很低。在这个策略下,期望的询问次数是 O(n2)。

那么,如何做到 O(n) 的复杂度呢?假设问 u 是否认识 v。答案只有两种:认识,则 u 不可能是名人;不认识,则 v 不可能是名人。这样,通过一次询问,就可以排除掉一个来宾。通过按对进行询问,通过 n/2 次询问就可以排除掉一半的人。在剩下的一半来宾中,递归地运用这个策略。令 T(n) 表示在 n 个来宾中找出这个名人所需的询问次数,则 T(n) = T(n/2) + O(n)。显然, T(n) = O(n)。

这个解法巧妙的地方在于运用了排除法。令人吃惊地是,在这道题目中,排除的效率比直接的搜寻高出 O(n) 的倍数。有时候,直接的搜索法比较低效时,可以考虑用排除的方法寻找答案。

《算法导论(第二版)》第22 章的问题 22.1-6 ( universal sink )有名人问题的有向图版本:用一个 n x n 的邻接矩阵表示一个 n 个结点的有向简单图。假设这个图上有一个结点,其入度为 n-1,出度为 0。用 O(n) 的时间找出这个结点。很显然,这个问题和上面的名人问题是一样的。

最后,我们不仅要问,这样的结点(或名人)最多能有多少个?简单地推理可知,最多只能有一个。

备注: 刚才把这个问题作为 quiz 问一学生物的mm,想看看非计算机的人是怎么思考这个问题的。她的解法似乎更简洁:一开始,找两个人,比如 a 和 b,问 a 是否认识 b。如果不认识,则排除 b,否则排除 a;然后再接着找 c 来和未排除的人进行询问,直到最后只剩下一个人,即是名人。很明显,只需要 n-1 次询问。关于复杂度的计算,最关键是观察便是,一次询问即可以排除一个人。因此,不论是什么顺序进行询问,所需的次数均是 n-1。

 

备注:本人撰写原文时,并不知道这个问题即为名人问题,现已更新。

原创粉丝点击