[BOJ] Q1219 오민식의 고민

Question

Language: Python

Difficulty: Gold 1

상당히 까다로운 문제이다. 문제에 주어진 조건을 분석해보면 간선을 이용하게 되면 비용이 발생하고, 도시에 도착하면 보상금이 발생한다.

도착지에 도착할 수 없으면 ‘gg’ 돈을 무한히 벌 수 있으면 ‘gee’ 벌 수 있는 최대값

우선 무한히 많이 벌 수 있다? –> cycle이 존재한다는 의미이다. –> 우리가 흔히 최단거리 알고리즘 중에 사이클과 연관 있는 것은 bellman-ford 알고리즘이다.

그러면 음수 사이클의 조건에 맞게 가중치를 역전 시킨다, 즉 간선의 가중치는 양수로 만들고, 도시의 보상금은 음수로 만들게 된다. 이렇게 되면 도시에 도착하게 되면 간선의 가중치-도시의 보상금으로 되어서 음수 값이 된다는 의미는 그 도시를 도착하게 될때 수익이 발생한다는 의미로 해석할 수 있다. 그렇게 되면 음수 사이클이 발생한다면 돈을 무한히 많이 벌게 되는 것이다.

Fail Code 1

def solution():
    for i in range(v):
        for j in range(v):
            if graph[i][j] != inf:
                graph[i][j] -=city_earnings[j]
    
    for times in range(v):
        for i in range(v):
            for j in range(v):
                if graph[i][j] != inf:

                    if distance[j] > distance[i]+graph[i][j]:
                        distance[j]=distance[i]+graph[i][j]

                        if times==v-1:
                            return False
    
    return True

처음에는 이렇게 음수 사이클이 존재하기만 하면 무조건 돈을 무한히 벌 수 있다고 생각했다.

하지만 아래의 그림과 같은 경우가 있다면?

Q1219

음수 사이클을 판단하는 것도 중요하지만, 사이클 내 도착지 노드가 존재하는 지를 확인해야된다.

Solution

from math import inf
from collections import deque

def solution():
    distances=[inf] *(v)
    distances[start]=-city_earnings[start]

    for i in range(e):
        edges[i][2]-=city_earnings[edges[i][1]]

    cycle=False
    reachable=False
    for times in range(v):
        for v1,v2,cost in edges:
            cost=distances[v1]+cost
            if distances[v2] > cost:
                distances[v2]=cost
                if times==v-1:
                    cycle=True
                    queue=deque([v2])
                    visited=[False]*(v)
                    
                    while queue:
                        vertex=queue.popleft()
                        visited[vertex]=True
                        
                        if vertex==end:
                            reachable=True
                        
                        for adj_vertex in graph[vertex]:
                            if not visited[adj_vertex]:
                                queue.append(adj_vertex)
    
    if distances[end]==inf:
        print("gg")
    else:
        if cycle and reachable:
            print("Gee")
        else:
            print(-distances[end])

if __name__ == "__main__":
v,start,end,e=map(int,input().split())
graph=[[] for _ in range(v)]
edges=[]
for _ in range(e):
        v1,v2,weight=map(int,input().split())
        graph[v1].append(v2)
        edges.append([v1,v2,weight])
city_earnings=list(map(int,input().split()))
solution()

그래서 위의 코드 처럼 bellman-ford 알고리즘을 통해 distances 배열을 최신화 시키고, 사이클이 생겼을 때는 bfs을 통해 도착지 노드가 사이클에 포함되어 있는지를 확인한다.

댓글남기기