所谓明星问题,其实就是在人群中找出一位明星人士。
问题思路:
该明星不认识人群中的其他人,但人人都认识这位明星。其实就是要研究某组依赖关系,寻找一个入手点。类似问题,在某个多线程应用程序中,线程之间可能存在着某种环形依赖的等待关系(所谓的死锁),我们需要找出一个不需要等任何线程,但其他所有线程都要依赖于它的线程。
无论我们用什么方式来包装这个问题,它的核心表现形式都是一个图结构。我们要寻找的是一个其他的所有节点对它都有入编,但它自身却没有出边的节点。
我们首先随机生成一个矩阵G:填充上0或者1。然后用c这个随机数设置好G的明星。满足:明星谁都不认识(G[c][i] = False)而大家都认识他(G[i][c] = True)
目标:找出明星是谁(就是这个c啦)
下面的代码中的关键步骤在于:
1.第一个for循环中,我们要找出明星在哪儿if G[u][v]: u = c如果u认识v那么,G[u][v]为真,那么u就不是明星,排除u,递增u(操作是u=c,因为c是递增的),如果u最后等于n,那么明星属于第v列。否则,G[u][v]为假,u不认识v。u可能是明星哦,那么检测u还认不认识其他的人,即v递增。如果v最后等于n,那么明星在第u行。
2.第二个for循环,主要是检测明星所在的行或者列,是否满足G[c][v]全都是False。而G[v][c]全都是True。
代码:
def celeb(G):
n = len(G)
u, v = 0, 1 # The first two
for c in range(2,n+1): # Others to check
if G[u][v]: u = c # u knows v? Replace u
else: v = c # Otherwise, replace v
if u == n: c = v # u was replaced last; use v
else: c = u # Otherwise, u is a candidate
for v in range(n): # For everyone else...
if c == v: continue # Same person? Skip.
if G[c][v]: break # Candidate knows other
if not G[v][c]: break # Other doesn't know candidate
else:
return c # No breaks? Celebrity!
return None # Couldn't find anyone
if __name__=="__main__":
from random import randrange
n=10
G = [[randrange(2) for i in range(n)] for i in range(n)]
c = randrange(n)
for i in range(n):
G[i][c] = True
G[c][i] = False
d=celeb(G)
print(d)
运行结果:
下面是生成的矩阵G:
[0, 1, 1, 1, True, 1, 1, 0, 0, 0]
[0, 0, 0, 0, True, 1, 1, 0, 0, 1]
[1, 0, 1, 1, True, 1, 1, 1, 0, 1]
[1, 1, 0, 0, True, 1, 0, 0, 0, 0]
[False, False, False, False, False, False, False, False, False, False]
[0, 1, 0, 1, True, 1, 1, 0, 0, 0]
[1, 1, 0, 0, True, 0, 0, 1, 0, 1]
[1, 1, 0, 1, True, 0, 1, 1, 0, 1]
[0, 1, 0, 0, True, 1, 0, 0, 1, 1]
[1, 1, 0, 0, True, 0, 1, 1, 1, 0]
执行完函数celeb(G)之后,d=4