問題文

空入力でテストを出力。トポロジカルソートは実は自力実装しなくてもgraphlibにある。(今回は不使用。toposort_graphlibの部分。)

# graph は隣接リスト(辞書)で管理

from collections import namedtuple, deque, defaultdict

Node = namedtuple('Node' , ["v", "cost"])

s = input('input:\n').strip()
for _ in range(1):
    if s == '':
        # test data
        V, E = 5, 5
        graph = {
            'A':[Node('D',1)],
            'B':[Node('C',1)],
            'C':[Node('E',1)],
            'D':[Node('B',100), Node('C',10)],
            'E':[]}
        break

    V, E = map(int, s.split())
    graph = defaultdict(list)
    for _ in range(E):
      src, dst, cost = input().upper().split()
      graph[src].append(Node(dst, int(cost)))
      graph[dst]  # default [] will be made when no entry

vertexes = sorted(graph.keys())
START = 'A'
END = vertexes[-1]

    
def toposort(graph):  # 深さ優先探索(DFS)を使うタイプ
    res = []
    visited = dict((v, False) for v in vertexes)
    is_start_found = False

    stack = deque()
    for v in vertexes:
        if is_start_found: break
        stack.append(v)
        while stack:
            u = stack.pop()
            if not visited[u]:  # 行きがけ
                stack.append(u)
                visited[u] = True
                for node in graph[u]:
                    if visited[node.v]: continue
                    stack.append(node.v)
            else:  # 帰りがけ
                res.append(u)
                if u == START:
                    is_start_found = True
                    break
    res.reverse()
    return res

def toposort_graphlib(graph):
    import graphlib
    
    # graphlib 用の隣接辞書は先行ノード管理型なので矢の向きが逆
    g = dict((v,[]) for v in graph.keys())
    for src_v, src_list in graph.items():
        for dst in src_list:
            g[dst.v].append(src_v)
    ts = graphlib.TopologicalSorter(g)
    return tuple(ts.static_order())


topo_order = toposort(graph)

# DP
dists = dict((v, -1) for v in vertexes)
dists[START] = 0
prevs = dict((v, -1) for v in vertexes)
for v in topo_order:
    if dists[v] == -1: continue  # STARTと繋がっていない
    for node in graph[v]:
        if dists[node.v] < dists[v] + node.cost:
            dists[node.v] = dists[v] + node.cost
            prevs[node.v] = v

def get_path(t):
    path = []
    while t != -1:
        path.append(t)
        t = prevs[t]
    path.reverse()
    return path

print()
c_path = get_path(END)
print(' -> '.join(c_path))
print(dists[END])

# 簡易チャート
print()
topo_s = [v for v in topo_order if dists[v] != -1]
c_edges = [c_path[i: i+2] for i in range(len(c_path)-1)]
print(''.join(f"{v:<7}" for v in topo_s))
for v in topo_s:
    src_i = topo_s.index(v)
    for node in graph[v]:
        dst_i = topo_s.index(node.v)
        is_critical = [v, node.v] in c_edges
        line_char = "*" if is_critical else "-"
        line = f"{node.cost:{line_char}^{(dst_i-src_i)*7}}"
        print(' '*7*src_i + line + '>')
A      D      B      C      E
***1***>
       **100**>
       ------10------>
              ***1***>
                     ***1***>

正しくない実装。入力によっては正答を返さないし、そもそも最長経路問題にダイクストラ法は上手くいかない。

def dijk(s):
  global d, prev
  d = [0] * V
  used = [False] * V
  prev = [-1] * V
  d[s] = 0
  while True:
    v = -1
    for u in range(V):
      if v!=-1 and cost[v][u] == INF: continue
      if not used[u] and (v==-1 or d[u] > d[v]): v = u
    if v == -1: break
    used[v] = True
    for u in range(V):
      if cost[v][u] == INF: continue
      if d[u] < d[v] + cost[v][u]:
        d[u] = d[v] + cost[v][u]
        prev[u] = v

def get_path(t):
  path = []
  while t != -1:
    path.append(chr(ord('A')+t))
    t = prev[t]
  return ' -> '.join(path[::-1])

V, E = map(int, input('input:\n').split())
INF = 987654321
cost = [ [ INF for _ in range(V+1) ] for _ in range(V+1) ]
for _ in range(E):
  a, b, c = input().split()
  a = ord(a) - ord('A')
  b = ord(b) - ord('A') 
  cost[a][b] = int(c)
dijk(0)
print(get_path(V-1))
print(d[V-1])

撃墜例


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS