假设我们有N个人,那里可能是一群名人。
每个人都知道每个名人,每个名人都只知道其他所有名人。
如果您获得了know x y
returns true or false
的功能,请确定名人群。
这个问题是识别一群名人,并且没有识别人中唯一的名人,例如http://www.geeksforgeeks.org/the-celebrity-problem/。
使用蛮力很容易。我可以构建N个人的所有可能的子序列并用条件过滤它们(每个人都知道每个名人,每个名人都只知道其他名人)。
我也知道必须只有一个名人组或没有。
证明:
假设我们有两个名人组,C1和C2。因为每个人都知道来自C1的ci,所以来自C2的每个cj也知道ci;对称地,每个ci都知道cj;所以C1和C2实际上属于一个组。所以我们最多只有一个名人组或没有。
关于可能的线性算法的任何想法?
修改
可能有一群名人,可能没有。
答案 0 :(得分:8)
是的,这可以在O(N)中进行(但请参见下面的第2次编辑)。这是一种算法。
列举从0到N-1的所有N个人。
int find_a_celebrity()
{
int C = 0; // C is a potential celebrity
for( int i=0 ; i<N ; ++i )
if( !know(i,C) ) // C is not a celebrity nor are all j<i, but i might be.
C = i;
for( int i=0 ; i<N ; ++i ) // Loop a second time to check everyone knows C.
if( !know(i,C) ) return -1;
return C;
}
int C = find_a_celebrity();
如果C==-1
那么就没有名人了。否则,集合{ y | know(C,y) }
是所有名人的集合。总而言之,所有N人最多需要3次迭代,因此可以及时发现O(N)
。
编辑:
// Output the set of celebrities
if( C == -1 ) std::cout << "There are no celebrities.";
else for( int i=0 ; i<N ; ++i ) if( know(C,i) ) std::cout << i << ' ';
std::cout << std::endl;
编辑2:
这个问题有两种解释:
上述算法针对情况#1解决了这个问题。这适用于案例#2,只要我们可以假设存在至少一个名人。否则,我们必须在最后确认潜在名人的名单只相互了解,这需要O(N*M)
时间,其中M是潜在名人的数量。
答案 1 :(得分:0)
编辑:我没有仔细阅读问题陈述。您没有所有边的列表,我们假设我们无法在线性时间内生成它。
这里的关键是每个人都知道每个名人。将此问题表示为有向邻接图,其中V顶点(名人)和E边(关系)连接它们。
通过列表E迭代计算每个人的知晓次数。名人被称为V-1次;其他人都是非名人。运行时间应为O(E)。
答案 2 :(得分:0)
作为一个名人是在不知情的情况下被人知道的状态。正常是知道的状态而不为人所知。因此,将每个人与他们旁边的人进行比较看起来像是:
foreach person in persons
{
knows = know(person, next_person)
isknown = know(next_person, person)
if knows and !isknown then normal
if !knows and isknown then celeb
if !knows and !isknown then normal
if knows and isknown then friends.add(person)
foreach friend in friends
{
alsoknows = know(person, friend)
if !alsoknows then normal; break;
}
}
答案 3 :(得分:0)
考虑所有N *(N-1)个可能的know(x,y)评估为真的情况。在这种情况下,所有N人都是名人。接下来,考虑除了知道(x,y)的N *(N-1)个评估之一之外的所有情况都是真的情况。根据{{3}},我希望我们应该将这种情况解释为没有名人。为了区分这两种情况,您需要评估所有可能的N *(N-1)对。
答案 4 :(得分:-1)
让candidates
成为所有n
人的列表。构建所有人的循环:
1 -> 2 -> ... -> n -> 1
。
现在,逐一检查knows k,k+1
。如果为真,则为k = k+1
并继续。如果knows k,k+1 == False
,,则k+1
不是名人,请将其从candidates
移除,然后再点击k,k+2
。
当我们在最后size(candidates)
轮次中没有删除任何人时,我们就完成了。
<强>证明:强>
如果名单中有名人,那么:
最后,我们将得到一个名人的循环。
如果列表中没有名人,请按照@Matt的回答。