問題
C – 友達の友達
回答
友達の友達を数える
集合を使い、友達の友達を探索して数えます。
import collections
N, M = map(int, input().split())
adjacent_dict = collections.defaultdict(list)
for _ in range(M):
a, b = map(int, input().split())
adjacent_dict[a].append(b)
adjacent_dict[b].append(a)
for i in range(1, N+1):
# 自身の友達
friends_i = adjacent_dict[i]
# 友達の友達
friends_of_friends = set()
for j in friends_i:
friends_j = adjacent_dict[j]
friends_of_friends |= set(friends_j)
# 友達の友達に自分自身がいる場合は除く
if i in friends_of_friends:
friends_of_friends.remove(i)
# 友達の友達から自身の友達を除く
diff_friends = friends_of_friends.difference(set(friends_i))
print(len(diff_friends))
頂点を2つ選び共通の友人がいるか調べる
集合を使い、2つの頂点ごとに、共通の友人がいるかを調べます。
import collections
N, M = map(int, input().split())
adjacent_dict = collections.defaultdict(list)
for _ in range(M):
a, b = map(int, input().split())
adjacent_dict[a].append(b)
adjacent_dict[b].append(a)
for i in range(1, N+1):
# iの友達
friends_i = set(adjacent_dict[i])
count = 0
for j in range(1, N+1):
# 自身を除く
if i == j:
continue
# jの友達
frineds_j = set(adjacent_dict[j])
# 友達は除く
if i in frineds_j:
continue
mutual_friends_ij = friends_i & frineds_j
# 自身、または直接の友達を除き、共通の友達がいる
if mutual_friends_ij:
count += 1
print(count)
ダイクストラ法
ダイクストラ法を用いて、全頂点間の距離を求め、各頂点から距離2の頂点の数えます。
scipy
scipy.sparse.csgraph.dijkstra を使ってみます。
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import dijkstra
N, M = map(int, input().split())
graph = [[0] * N for _ in range(N)]
for _ in range(M):
a, b = map(int, input().split())
graph[a-1][b-1] = 1
graph[b-1][a-1] = 1
graph = csr_matrix(graph)
dist_matrix = dijkstra(graph)
for row in dist_matrix:
counts = 0
for dist in row:
if dist == 2:
counts += 1
print(counts)
自分で実装
ダイクストラ法を自分で実装してみます。
import collections
import heapq
N, M = map(int, input().split())
# 隣接リスト
adjacent_dict = collections.defaultdict(list)
for _ in range(M):
a, b = map(int, input().split())
adjacent_dict[a].append(b)
adjacent_dict[b].append(a)
# 全てのノードに対してダイクストラ法を適用
for i in range(1, N+1):
# 全ての距離を最大値に指定
distance_dict = collections.defaultdict(lambda: float('inf'))
# 自身への距離は0
distance_dict[i] = 0
# (距離, 頂点)の優先度付きキュー
priority_queue = []
heapq.heappush(priority_queue, (0, i))
# 訪問済みフラグ
visited = collections.defaultdict(bool)
while priority_queue:
# 距離が最小であるノード
cur_dist, cur_node = heapq.heappop(priority_queue)
# 訪問済みフラグ
if visited[cur_node]:
continue
visited[cur_node] = True
# 隣接ノードとの距離
for next_node in adjacent_dict[cur_node]:
if visited[next_node]:
continue
new_dist = cur_dist + 1
# 新しい距離が短い場合は距離を更新
if distance_dict[next_node] > new_dist:
distance_dict[next_node] = new_dist
heapq.heappush(priority_queue, (new_dist, next_node))
cnt = 0
for val in distance_dict.values():
if val == 2:
cnt += 1
print(cnt)
ワーシャルフロイド法
ワーシャルフロイド法を用いて、全頂点間の距離を求め、各頂点から距離2の頂点の数えます。
scipy
scipy.sparse.csgraph.floyd_warshall を使ってみます。
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import floyd_warshall
N, M = map(int, input().split())
graph = [[0] * N for _ in range(N)]
for _ in range(M):
a, b = map(int, input().split())
graph[a-1][b-1] = 1
graph[b-1][a-1] = 1
graph = csr_matrix(graph)
dist_matrix = floyd_warshall(graph)
for row in dist_matrix:
cnt = 0
for dist in row:
if dist == 2:
cnt += 1
print(cnt)
自分で実装
ワーシャルフロイド法を自分で実装してみます。
N, M = map(int, input().split())
# 距離行列の生成
inf = float('inf')
dist_matrix = [[inf] * N for _ in range(N)]
for i in range(N):
dist_matrix[i][i] = 0
for _ in range(M):
a, b = map(int, input().split())
dist_matrix[a-1][b-1] = 1
dist_matrix[b-1][a-1] = 1
# ワーシャルフロイド
for k in range(N):
for i in range(N):
for j in range(N):
dist_matrix[i][j] = min(dist_matrix[i][j],
dist_matrix[i][k] + dist_matrix[k][j])
for row in dist_matrix:
cnt = 0
for dist in row:
if dist == 2:
cnt += 1
print(cnt)