問題
有向非巡回グラフであり、DP の更新順序が非自明な問題です。
メモ化再帰を使うか、トポロジカルソートを使います。
解き方は以下を参考にしています。
Educational DP Contest の F ~ J 問題の解説と類題集 G 問題 – Longest Path
回答
メモ化再帰
import sys
# 許容する再帰処理の回数を変更
sys.setrecursionlimit(10**5+10)
# input処理を高速化する
input = sys.stdin.readline
def chmax(a, b):
""" 最大値を返す関数 """
if a >= b:
return a
else:
return b
def main():
# 入力
N, M = map(int, input().split())
# 隣接関係は隣接リストで管理する
lst_edge = [[] for _ in range(N)]
for _ in range(M):
x, y = map(int, input().split())
# 最初のindexをゼロにする
lst_edge[x-1].append(y-1)
# dp[v] := ノードvを始点とした時の有向パスの長さの最大値
# -1 未訪問で初期化。
dp = [-1] * N
# メモ化再帰
def rec(v):
# 既に更新済み
if dp[v] != -1:
return dp[v]
ans = 0
lst_nv = lst_edge[v]
for nv in lst_nv:
ans = chmax(ans, rec(nv) + 1)
dp[v] = ans
return dp[v]
# 全ての点に対して更新する
ans = 0
for v in range(N):
ans = chmax(ans, rec(v))
print(ans)
main()
import sys
# 許容する再帰処理の回数を変更
sys.setrecursionlimit(10**5+10)
# input処理を高速化する
input = sys.stdin.readline
def chmax(a, b):
""" 最大値を返す関数 """
if a >= b:
return a
else:
return b
def main():
# 入力
N, M = map(int, input().split())
# 隣接関係は隣接リストで管理する
lst_edge = [[] for _ in range(N)]
for _ in range(M):
x, y = map(int, input().split())
# 最初のindexをゼロにする
lst_edge[x-1].append(y-1)
# dp[v] := ノードvを始点とした時の有向パスの長さの最大値
# -1 未訪問で初期化。
dp = [-1] * N
# メモ化再帰
def rec(v):
# 既に更新済み
if dp[v] != -1:
return dp[v]
ans = 0
lst_nv = lst_edge[v]
for nv in lst_nv:
ans = chmax(ans, rec(nv) + 1)
dp[v] = ans
return dp[v]
# 全ての点に対して更新する
ans = 0
for v in range(N):
ans = chmax(ans, rec(v))
print(ans)
main()
import sys # 許容する再帰処理の回数を変更 sys.setrecursionlimit(10**5+10) # input処理を高速化する input = sys.stdin.readline def chmax(a, b): """ 最大値を返す関数 """ if a >= b: return a else: return b def main(): # 入力 N, M = map(int, input().split()) # 隣接関係は隣接リストで管理する lst_edge = [[] for _ in range(N)] for _ in range(M): x, y = map(int, input().split()) # 最初のindexをゼロにする lst_edge[x-1].append(y-1) # dp[v] := ノードvを始点とした時の有向パスの長さの最大値 # -1 未訪問で初期化。 dp = [-1] * N # メモ化再帰 def rec(v): # 既に更新済み if dp[v] != -1: return dp[v] ans = 0 lst_nv = lst_edge[v] for nv in lst_nv: ans = chmax(ans, rec(nv) + 1) dp[v] = ans return dp[v] # 全ての点に対して更新する ans = 0 for v in range(N): ans = chmax(ans, rec(v)) print(ans) main()
トポロジカルソート
dequeオブジェクトを使います。
import sys
import collections
# input処理を高速化する
input = sys.stdin.readline
def chmax(a, b):
""" 最大値を返す関数 """
if a >= b:
return a
return b
def main():
# 入力
N, M = map(int, input().split())
# 隣接関係は隣接リストで管理する
lst_edge = [[] for _ in range(N)]
# 各頂点の入力辺の本数
deg = [0] * N
for _ in range(M):
x, y = map(int, input().split())
# 最初のindexをゼロにする
lst_edge[x-1].append(y-1)
deg[y-1] += 1
# 入力辺を持たない頂点をqueueに入れる
que = collections.deque()
for v in range(N):
if deg[v] == 0:
que.append(v)
# 各頂点の最初に入力辺を持たなかった点からの距離
dp = [0] * N
# For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
# https://www.python.org/dev/peps/pep-0008/#programming-recommendations
while que:
v = que.popleft()
lst_nv = lst_edge[v]
for nv in lst_nv:
# エッジ(v, nv)をグラフから削除する
deg[nv] -= 1
if deg[nv] == 0:
# エッジがなくなったことで、入力辺がなくなったらqueueに入れる
que.append(nv)
# 最初に入力辺を持たなかった点からの距離
dp[nv] = chmax(dp[nv], dp[v] + 1)
print(max(dp))
main()
import sys
import collections
# input処理を高速化する
input = sys.stdin.readline
def chmax(a, b):
""" 最大値を返す関数 """
if a >= b:
return a
return b
def main():
# 入力
N, M = map(int, input().split())
# 隣接関係は隣接リストで管理する
lst_edge = [[] for _ in range(N)]
# 各頂点の入力辺の本数
deg = [0] * N
for _ in range(M):
x, y = map(int, input().split())
# 最初のindexをゼロにする
lst_edge[x-1].append(y-1)
deg[y-1] += 1
# 入力辺を持たない頂点をqueueに入れる
que = collections.deque()
for v in range(N):
if deg[v] == 0:
que.append(v)
# 各頂点の最初に入力辺を持たなかった点からの距離
dp = [0] * N
# For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
# https://www.python.org/dev/peps/pep-0008/#programming-recommendations
while que:
v = que.popleft()
lst_nv = lst_edge[v]
for nv in lst_nv:
# エッジ(v, nv)をグラフから削除する
deg[nv] -= 1
if deg[nv] == 0:
# エッジがなくなったことで、入力辺がなくなったらqueueに入れる
que.append(nv)
# 最初に入力辺を持たなかった点からの距離
dp[nv] = chmax(dp[nv], dp[v] + 1)
print(max(dp))
main()
import sys import collections # input処理を高速化する input = sys.stdin.readline def chmax(a, b): """ 最大値を返す関数 """ if a >= b: return a return b def main(): # 入力 N, M = map(int, input().split()) # 隣接関係は隣接リストで管理する lst_edge = [[] for _ in range(N)] # 各頂点の入力辺の本数 deg = [0] * N for _ in range(M): x, y = map(int, input().split()) # 最初のindexをゼロにする lst_edge[x-1].append(y-1) deg[y-1] += 1 # 入力辺を持たない頂点をqueueに入れる que = collections.deque() for v in range(N): if deg[v] == 0: que.append(v) # 各頂点の最初に入力辺を持たなかった点からの距離 dp = [0] * N # For sequences, (strings, lists, tuples), use the fact that empty sequences are false. # https://www.python.org/dev/peps/pep-0008/#programming-recommendations while que: v = que.popleft() lst_nv = lst_edge[v] for nv in lst_nv: # エッジ(v, nv)をグラフから削除する deg[nv] -= 1 if deg[nv] == 0: # エッジがなくなったことで、入力辺がなくなったらqueueに入れる que.append(nv) # 最初に入力辺を持たなかった点からの距離 dp[nv] = chmax(dp[nv], dp[v] + 1) print(max(dp)) main()
sequenceが空かどうかの判定
「空のsequenceはFlaseである」ということを使うこと。PEP 8推奨だし、多分一番速い。
Yes: if not seq:
if seq:
No: if len(seq):
if not len(seq):
Yes: if not seq:
if seq:
No: if len(seq):
if not len(seq):
Yes: if not seq: if seq: No: if len(seq): if not len(seq):