aacord’s memo

abcを中心にpythonで解いた問題のメモ、整理をしています。緑になった。

abc 137 E - Coins Respawn (python)

経過時間*P 枚コインを失い、辺を通るのに1分かかり、辺上でC枚のコインを得るので、
辺を通ったときにかかるコスト(-コインの数)を -C+P 枚とすれば、最短路問題に帰着できる。今回は負の辺があるのでベルマンフォード法を使う。
面倒なのは、頂点1からNに向かう途中でコストの総和が負になるようなループが存在すると答えが -float('inf') (答えは -1) になるのが面倒。
これを条件を分割して考えると、
まず1からNに向かう経路を取り出す、
取り出した経路に負のループが存在したら -1 を出力(負のループがあるかどうかは最短路の更新回数がN回以上あるかで判断できる。)存在しなかったら最短コスト* -1 を出力する

from collections import deque
def use_path(n,start,es):
    q = deque()
    chk = [False] * n
    q.append(start)
    chk[start] = True
    used = {start}
    while len(q) > 0:
        node = q.popleft()
        for nex in es[node]:
            if not chk[nex]:
                chk[nex] = True
                q.append(nex)
                used.add(nex)
    return used
  
def belman(s,g,n,es):
    d = [10**10] * n
    d[s] = 0
    fin = False
    cnt = 0
    while True:
      update = False
      for p,q,r in es:
        if d[p] != 10**10 and d[q] > d[p] + r:
          d[q] = d[p] + r
          update = True
      cnt += 1
      if not update:
        fin = True
        break
      if cnt > n+1:
          break      
    if fin:
        return max(0,-d[g])
    else:
        return -1   
  
n,m,p = map(int, input().split())

l = [[] for i in range(n)]
r = [[] for i in range(n)]
edges = []

for i in range(m):
    a,b,c = map(int, input().split())
    a -= 1
    b -= 1
    l[a].append(b)
    r[b].append(a)
    edges.append((a,b,-c+p))
    
use_nodes = use_path(n,0,l) & use_path(n,n-1,r)
es = [(a,b,c) for a,b,c in edges if a in use_nodes and b in use_nodes]
print(belman(0,n-1,n,es))