For Programmer

백준 1647번 파이썬 문제풀이(도시 분할 계획) - (크루스칼) 본문

코팅테스트/백준 문제 모음

백준 1647번 파이썬 문제풀이(도시 분할 계획) - (크루스칼)

유지광이 2022. 4. 27. 22:16
728x90

https://www.acmicpc.net/problem/1647

 

1647번: 도시 분할 계획

첫째 줄에 집의 개수 N, 길의 개수 M이 주어진다. N은 2이상 100,000이하인 정수이고, M은 1이상 1,000,000이하인 정수이다. 그 다음 줄부터 M줄에 걸쳐 길의 정보가 A B C 세 개의 정수로 주어지는데 A번

www.acmicpc.net


간단히 크루스칼 코드만 알고 있다면 쉽게 해결할 수 있다. 조건 2가지 ( 분리된 두 마을 사이에 있는 길들은 필요가 없으므로 없앨 수 있다. , 임의의 두 집 사이에 경로가 항상 존재하게 하면서 길을 더 없앨 수 있다.) 가 있는데 그 중 분리된 두 마을 사이에 있는 길들은 필요가 없으므로 없앨 수 있다. 의 조건을 생각하기가 까다로울 수 있다. 

 

문제를 잘보면 한 마을안에는 최소 1개의 집이 존재해야한다고 한다. 반대로 생각해보면 집을 1개만 남겨도 된다는 뜻이다. 따라서 크루스칼로 최소신장 트리를 만들면서 마지막에 연결되는 길만 없애주면 무조건 마을 2개를 만들 수 있으며 최소길이로 만들 수 있다.

 

import sys

input = sys.stdin.readline


def find(x):
    if x != parent[x]:
        parent[x] = find(parent[x])
    return parent[x]


def union_(a, b):
    a = find(a)
    b = find(b)

    # 이미 부모가 같다면 리턴
    if a == b:
        return

    if rank[a] > rank[b]:
        parent[b] = a
    elif rank[a] < rank[b]:
        parent[a] = b
    else:
        parent[a] = b
        rank[b] += 1


N, M = map(int, input().split())

graph = []
parent = [i for i in range(N + 1)]  # 부모를 저장
rank = [0] * (N + 1)  # 각 노드마다 랭크를 저장
for i in range(M):
    a, b, cost = map(int, input().split())
    graph.append((a, b, cost))

graph.sort(key=lambda x: x[2])  # 마을의 비용을 오름차순으로 정렬
ans = 0  # 연결된 마을 길이의 합
end_v = 0  # 마지막에 연결된 마을 길이를 저장
for i in graph:

    if find(i[0]) != find(i[1]):
        union_(i[0], i[1])
        ans += i[2]  # 마을의 연결 비용들을 계속 더해주고
        end_v = i[2]  # 마지막에 연결된 마을 연결 비용을 저장

print(ans - end_v)  # 마지막에 연결된 연결 비용만 빼준 체 출력
728x90
Comments