在n个人中最多找到(n / 2)-1个骗子的最快算法

时间:2011-05-02 16:16:59

标签: algorithm find compare

以下是我的情景:

这个问题是关于骗子和真相讲述者的问题,但它在确定复杂系统的哪些组件是好的(正常运行)和哪些是错误方面具有实际应用。假设我们有一个n人的社区,我们知道一个整数t< n / 2,其中有大多数人都是骗子。这并不是说实际上有说谎者,而是说最多只有说谎者。

我认为真相讲述者总是真实而正确,而骗子可能会说出错误答案或正确答案。

我们将通过连续挑选一对人来识别社区中的骗子,(X,Y)说,并问X:Y是骗子吗?回答是“是”或“否”;

查找所有骗子的最佳算法(最小步数)是多少?

5 个答案:

答案 0 :(得分:7)

具有O(n)的最佳预期运行时间和优异常数的随机算法:

  1. 随意选择
  2. 询问其他人是否是骗子,直到一个选项(“是”或“否”)具有权重> n / 2(即直到超过n / 2的人给出相同的答案) 多数人决定(这是关键的观察!)。
  3. 如果他不是骗子,那么就对剩下的人进行迭代,然后只让他询问每个人是否是骗子(因为我们确定他说的是实话)。
  4. 如果他是个骗子,请将他带出小组,然后回到1。
  5. 关键的观察是,如果我们向每个人询问一个人,多数意见必须是正确的(因为大多数真相计票员)。稍微技术性的是,如果我们首先挑选一个非骗子并问别人,假设所有骗子撒谎,我们将达到50-50,那么我们如何决定哪一方说实话?这不是一个问题,因为如果我们首先选择一个非骗子,我们只能达到50-50,所以我们这个人确实是真理出纳员。

    我们必须随机选择的预期人数是O(1)(这是这个问题中最可怕的部分,因为它可能是家庭作业,我会跳过证明,但暗示一个简单的证据:几何分布),这意味着我们将在O(1)* O(n)时间内找到我们的真实出纳员和可靠的来源,从那里它是另一个O(n)直到完成。总计,O(n)。

答案 1 :(得分:5)

关于这一主题的一篇好文章是Leslie Lamport的“拜占庭将军问题”,可从以下网站获取 http://research.microsoft.com/en-us/um/people/lamport/pubs/byz.pdf

不是直接的解决方案,而是为感兴趣的人提供良好的背景阅读。

答案 2 :(得分:3)

你说一个骗子可能说实话或撒谎。在我看来,这使问题变得困难。我提供了一个特殊情况下的解决方案,其中一个骗子总是谎言。

G成为感兴趣的群体。选择组中的任意成员,X说。请注意,询问X“的程序是Y骗子?”如果XY都是真相出纳员,或两者都是骗子,则回答为“否”,否则回答为“是”。因此,问X“是Y骗子?”对于Y中的每个GX除外),您可以找出哪些成员YX位于同一“团队”中。由于必须有比说谎者更多的真相出纳员这一事实,这使您可以识别哪个“团队”X正在进行,之后识别说谎者很简单。

答案 3 :(得分:1)

我的解决方案的伪代码,与Davin的解决方案基本相同。一个值得注意的区别是,您只需要达到最大可能的剩余骗子+ 1的共识。

set unknown = all
set known_true = {}
set known_lie = {}

while known_true.is_empty()
  voted_lie = {}
  voted_true = {}
  truth_votes = 0
  lie_votes = 0
  to_check = unknown.get(0)
  while truth_votes < t - known_lie.size() + 1 && lie_votes < t - known_lie.size() + 1:
    checker = unknown.get_next()
    if checker.is_liar(to_check):
      lie_votes++
      voted_lie.add(checker)
    else
      truth_votes++
      voted_true.add(checker)

  if truth_votes > t + 1:
    unknown.remove(to_check)
    known_true.add(to_check)
    known_lie.add_all(voted_lie)
    unknown.remove_all(voted_lie)
  else:
    unknown.remove(to_check)
    known_lie.add(to_check)
    known_lie.add_all(voted_true)
    unknown.remove_all(voted_true)


while not unknown.is_empty() && known_liar.size() < t:
  to_check = unknown.get(0)
  if known_true.get(0).is_liar(to_check):
    unknown.remove(to_check)
    known_lie.add(to_check)
  else
    unknown.remove(to_check)
    known_true.add(to_check)

答案 4 :(得分:0)

如果您查询所有对,那么真相出纳员将显示为大小的唯一最大团体&gt; N / 2。我会把它留给那些舒适的破坏性作业问题进行优化。