D - 都市ネットワーク / City Network 解説 by admin
Qwen3-Coder-480B概要
都市間の最短距離と代表者の忍耐力を用いて、条件を満たす「友好ペア」の総数を求める問題です。
考察
この問題では、まず各都市間の最短距離を求める必要があります。都市数 \(N\) は最大 400 なので、全点対間の最短距離を求めるのに適したアルゴリズムとして Dijkstra法 を各頂点から実行する方法が考えられます(Floyd-Warshall法より高速かつ実装が簡単です)。
次に、各代表者 \(i\) について、他のすべての都市 \(j\) に対して \(d(i, j) > S_i\) であるかどうかを判定し、そのような都市の数をカウントして 不満の個数 \(C_i\) を求めます。
最後に、すべての異なる代表者ペア \((i, j)\)(\(i < j\))について、以下の2条件を満たすものを「友好ペア」としてカウントします:
- \(d(i, j) \leq S_i\) かつ \(d(i, j) \leq S_j\):互いに相手の都市に不満を抱かない。
- \(C_i = C_j\):両者の不満の個数が等しい。
素朴な解法では、各頂点からのDijkstraをナイーブに行うと全体で \(O(N \cdot (N + M) \log N)\) となりますが、制約上これでも十分高速です。逆に、Floyd-Warshallを使うと \(O(N^3)\) かかり、TLEする可能性があります。
アルゴリズム
グラフの構築
入力から無向グラフを隣接リスト形式で構築します。全点対最短距離の計算
各頂点 \(i\) に対して Dijkstra 法を実行し、\(d(i, j)\) を求めたテーブルDを作成します。不満の個数の計算
各代表者 \(i\) について、\(d(i, j) > S_i\) となる都市 \(j\) の数を数え、配列Cに保存します。友好ペアのカウント
全ての \(i < j\) について、以下の条件を満たすペアを数えます:- \(D[i][j] \leq S[i]\) かつ \(D[i][j] \leq S[j]\)
- \(C[i] == C[j]\)
計算量
- 時間計算量: \(O(N \cdot (N + M) \log N)\)
- 空間計算量: \(O(N^2 + M)\)
実装のポイント
頂点番号は入力で1-indexedで与えられるため、内部処理では0-indexedに変換する必要があります。
Dijkstra法では優先度付きキュー(
heapq)を使用して効率的に最小距離頂点を取り出すようにしましょう。無限大を表す値として
float('inf')を使用しており、比較演算も正しく動作します。ソースコード
import heapq
import sys
def dijkstra(graph, start, n):
dist = [float('inf')] * n
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heapq.heappop(pq)
if d > dist[u]:
continue
for v, w in graph[u]:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
heapq.heappush(pq, (dist[v], v))
return dist
def main():
import sys
input = sys.stdin.read
data = input().split()
idx = 0
N = int(data[idx]); idx += 1
M = int(data[idx]); idx += 1
S = [int(data[idx + i]) for i in range(N)]
idx += N
graph = [[] for _ in range(N)]
for _ in range(M):
u = int(data[idx]) - 1; idx += 1
v = int(data[idx]) - 1; idx += 1
w = int(data[idx]); idx += 1
graph[u].append((v, w))
graph[v].append((u, w))
# 全点対最短距離を計算
D = []
for i in range(N):
dist = dijkstra(graph, i, N)
D.append(dist)
# 各代表者の不満の個数 C_i を計算
C = [0] * N
for i in range(N):
count = 0
for j in range(N):
if i == j:
continue
if D[i][j] > S[i]:
count += 1
C[i] = count
# 友好ペアの数を数える
ans = 0
for i in range(N):
for j in range(i + 1, N):
if D[i][j] <= S[i] and D[i][j] <= S[j] and C[i] == C[j]:
ans += 1
print(ans)
if __name__ == "__main__":
main()
この解説は qwen3-coder-480b によって生成されました。
投稿日時:
最終更新: