1. 程式人生 > >嗶哩嗶哩2018.9.21筆試 小A最多會新認識多少人

嗶哩嗶哩2018.9.21筆試 小A最多會新認識多少人

題目描述

小A參加一個n人的活動,每個人都有一個編號(0<=i<=n-1),其中有m對相互認識,在活動中兩個人可以通過互相都認識都認識的一個人介紹認識。現在問活動結束後,小A最多會認識多少人? 輸入: 第一行是聚會人數n 第二行是小A的編號a 接下來m行為互相認識的對,以’,'分割 輸出: 小A最多會認識多少人的人數。 樣例輸入: 7 5 6 1,0 3,1 4,1 5,3 6,1 6,5 樣例輸出: 3 提示: 小A新認識的人為【0,1,4】

深度遍歷

在這裡插入圖片描述 1.分析這句話“個人可以通過互相都認識都認識的一個人介紹認識”,所以最終,有間接認識關係的人都會互相認識。

2.該問題是一個無向圖的深度遍歷。

3.在深度遍歷的過程中,把小A新認識的人加入一個集合中,最後輸出這個集合的長度。

4.注意不要把小A和小A初始已經認識的朋友加入集合中

5.考慮到整個圖可能是不連通的,所以必須從a開始進行深度遍歷

n = eval(input())
a = eval(input())
m = eval(input())
from collections import defaultdict
d = defaultdict(list)
for i in range(m):
    start,end  = map(int,input().split(','))
    d[start].append(end)
d[end].append(start) visited = [False]*n visited[a] = True friend = set() def recur(i): if (i != a) and (i not in d[a]): #注意不要把小A和小A初始已經認識的朋友加入集合中 friend.add(i) if (d[i] == []): return for re in d[i]: if visited[re] == False: visited[re] =
True recur(re) visited[re] = False recur(a) print(len(friend))

但該程式碼中,有些遞迴分支會作一些無用功,因為可能會深度遍歷到小A的初始朋友中去。比如,假設遞迴初始從5到了3,在這之後的遞迴分支,程式會遞迴到6去,但6是小A的初始朋友,則遞迴不應該遞迴到6。所以上述程式碼還可以優化。

深度遍歷+層次圖

利用層次圖的思想,起碼節點5的層次為0,那麼3和6的層次為1,1的層次為2,以此類推。 所以,當我們遍歷到層次為1的節點時,其他同樣層次為1的節點的visited也應該設定為True,這樣就能克服之前程式碼的缺點,避免遞迴走到小A的初始朋友。 在這裡插入圖片描述

n = eval(input())
a = eval(input())
m = eval(input())
from collections import defaultdict
d = defaultdict(list)
for i in range(m):
    start,end  = map(int,input().split(','))
    d[start].append(end)
    d[end].append(start)

visited = [False]*n
visited[a] = True
newfriend = set()

def mark(li):
    for i in li:
        visited[i] = True
        
def antiMark(li):
    for i in li:
        visited[i] = False    

def recur(i,step):
    if step >= 2:
        newfriend.add(i)
    if (d[i] == []):
        return
    for re in d[i]:
        if visited[re] == False:
            if step == 0:
                mark(d[i])
            visited[re] = True
            recur(re,step+1)
            visited[re] = False
            if step == 0:
                antiMark(d[i])
                
recur(a,0)
print(len(newfriend))

mark函式用來標記層次為1的節點為True,antiMark函式用來當遞迴返回時反標記層次為1的節點。 另外,遞迴函式第二個引數step代表遞迴的深度,當遞迴的step>=2時,那麼此時的i肯定是新認識的朋友。