AtCoder Beginner Contest 160 D – Line++ をPython3で解く

Share

AtCoder上にある問題のうち、AtCoder Problemsでdiff 800以上と判定されているものを順番に解いていく企画。
基本的な考え方は全てコード中のコメントに入れてあるので、参照のこと。

出典:
AtCoder Beginner Contest 160 D – Line++

グラフ上の最短距離に関する問題。BFSで解いてみたものの、公式解説とは別の解法だった。まあ、どちらでもよさそうではある。通れば正義。

# AtCoder Beginner Contest 160 D - Line++
# https://atcoder.jp/contests/abc160/tasks/abc160_d
# tag: グラフ BFS 距離 最短距離 数え上げ

# 最初に思いついたのは、それぞれの開始地点から、BFSで全探索。
# 制約 (3 <= N <= 2000) で、O(N^2) なのでちゃんと間に合う。
# Pypyなら230msくらいで余裕。Python提出でも1300msくらい。
# あまり何も考えずに書けるので、まあこれでもいいのでは?……という感じ。

from collections import deque
def main():
# 内部的には 0-indexed にしておく
N, X, Y = map(int, input().split())
X -= 1
Y -= 1

# グラフ構築
paths = [[] for _ in range(N)]
for i in range(N-1):
paths[i].append(i+1)
paths[i+1].append(i)
paths[X].append(Y)
paths[Y].append(X)

# 最短距離ごとの組み合わせ数を探索の際に数えていく
# result[x]: 最短距離 x の組み合わせ数
result = [0] * N

# 開始地点 (1 ~ N) を全部試す
for start in range(N):
dist = [-1] * N
dist[start] = 0
queue = deque([start])

# いつものBFS
while queue:
now = queue.popleft()
for nxt in paths[now]:
if dist[nxt] != -1:
continue
dist[nxt] = dist[now] + 1
queue.append(nxt)

# 距離が確定した際、result で数えておく
result[dist[nxt]] += 1

# 往復で数えているので、2 で割って出力
for r in result[1:]:
print(r//2)

# main()

# 公式解説のやり方は、開始地点と終了地点を定めての全探索。
# 距離については、経路(X-Y) を通る場合と通らない場合で
# 分けてやると、O(1) で計算できる。
# さっきのやり方は往復で見てしまっている分無駄があるので、
# こちらのほうが速い。
# 実際に(最大効率で書けば)大体半分の実行時間になるのが、
# ちょっと面白い(当たり前ではあるが)。

def main2():
N, X, Y = map(int, input().split())

# ここでは、関数を分けて少し分かりやすく書いている
def get_dist(a, b):
# a -> b 直行
d1 = abs(a - b)

# a -> X -> Y -> b
d2 = abs(a - X) + 1 + abs(b - Y)

# a -> Y -> X -> b
d3 = abs(a - Y) + 1 + abs(b - X)

# 経路は上記のどれかになるので、最小のものを返す
return min(d1, d2, d3)

result = [0] * N

for start in range(1, N):
for goal in range(start+1, N+1):
result[get_dist(start, goal)] += 1

for r in result[1:]:
print(r)

# main2()

Share

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です