1. 문제
다솜이는 불우이웃 돕기 활동을 하기 위해 무엇을 할지 생각했다. 마침 집에 엄청나게 많은 랜선이 있다는 것을 깨달았다. 마침 랜선이 이렇게 많이 필요 없다고 느낀 다솜이는 랜선을 지역사회에 봉사하기로 했다.
다솜이의 집에는 N개의 방이 있다. 각각의 방에는 모두 한 개의 컴퓨터가 있다. 각각의 컴퓨터는 랜선으로 연결되어 있다. 어떤 컴퓨터 A와 컴퓨터 B가 있을 때, A와 B가 서로 랜선으로 연결되어 있거나, 또 다른 컴퓨터를 통해서 연결이 되어있으면 서로 통신을 할 수 있다.
다솜이는 집 안에 있는 N개의 컴퓨터를 모두 서로 연결되게 하고 싶다.
N개의 컴퓨터가 서로 연결되어 있는 랜선의 길이가 주어질 때, 다솜이가 기부할 수 있는 랜선의 길이의 최댓값을 출력하는 프로그램을 작성하시오.
입력
첫째 줄에 컴퓨터의 개수 N이 주어진다. 둘째 줄부터 랜선의 길이가 주어진다. i번째 줄의 j번째 문자가 0인 경우는 컴퓨터 i와 컴퓨터 j를 연결하는 랜선이 없음을 의미한다. 그 외의 경우는 랜선의 길이를 의미한다. 랜선의 길이는 a부터 z는 1부터 26을 나타내고, A부터 Z는 27부터 52를 나타낸다. N은 50보다 작거나 같은 자연수이다.
출력
첫째 줄에 다솜이가 기부할 수 있는 랜선의 길이의 최댓값을 출력한다. 만약, 모든 컴퓨터가 연결되어 있지 않으면 -1을 출력한다.
2. 정답코드
# @Date : 2024-09-27 14:13:23 # @Author : ecodev # @Link : http://ecodev-blog.vercel.app import sys input = sys.stdin.readline ############ ---- Input Functions ---- ############ def inp(): return(int(input())) def inlt(): return(list(map(int, input().split()))) def insr(): s = input() return(list(s[:len(s) - 1])) def invr(): return(map(int, input().split())) def find_parent(parent, x): if parent[x] != x: parent[x] = find_parent(parent, parent[x]) return parent[x] def union(parent, a, b): a = find_parent(parent, a) b = find_parent(parent, b) if a < b: parent[b] = a else: parent[a] = b n = inp() ls = [list(input().rstrip()) for _ in range(n)] parent = [x for x in range(n + 1)] edges = [] total = 0 for i in range(n): for j in range(n): if ls[i][j] != "0": if "a" <= ls[i][j] <= "z": edges.append((ord(ls[i][j]) - ord("a") + 1, i + 1, j + 1)) total += ord(ls[i][j]) - ord("a") + 1 else: edges.append((ord(ls[i][j]) - ord("A") + 27, i + 1, j + 1)) total += ord(ls[i][j]) - ord("A") + 27 edges.sort() result = 0 for edge in edges: cost, a, b = edge if find_parent(parent, a) != find_parent(parent, b): union(parent, a, b) result += cost for i in range(1, n + 1): parent[i] = find_parent(parent, i) if len(set(parent)) == 2: print(total - result) else: print(-1)
3. 생각한 방향 및 설명
우선 문제에서 정답으로 구현해야하는 조건이
기부할 수 있는 랜선 길이의 최댓값
이다.그래서 각각의 컴퓨터를 노드로 생각해서 그래프를 떠올릴 수 있었고, 서로 연결된 랜선들은 각 컴퓨터(노드)들이 연결되있는 간선이라고 생각해 볼 수 있었다.
결국 최대로 기부를 하려면 컴퓨터들끼리 서로 최소한으로 연결돼있으면 되기때문에 여기서 연상할 수 있는 알고리즘 기법은
크루스칼
알고리즘이다. 즉 최소 신장 트리를 구현해서 그 최소 신장 트리의 간선길이들을 전부 더한 값을 전체 랜선길이에서 빼주면 최대로 기부할 수 있는 길이가 나오게 된다.
이 문제는 길이가 숫자로 주어지지 않고 문자로 주어졌다. 문자에 대응되는 숫자로 길이를 변환해주어야 하는데 여기서
ord()
라는 문자를 아스키코드로 변환시켜주는 함수를 사용하였다(그 반대는 chr()
이 있다).그리고 추가 조건에서 모든 컴퓨터가 연결되어 있지 않으면 -1을 출력하라고 하였다.
이 부분에서 조금 헤맸었는데 union-find를 통해 이 조건도 해결할 수 있었다.
우선 하나의 트리를 생성하는 것이기 때문에 루트노드가 존재할 것이라 생각했고, 결국 모든 컴퓨터들은 하나의 컴퓨터(루트노드)에 연결돼있을 것이라 생각했다.
따라서 parent리스트에는 0값을 제외한 숫자중 하나의 숫자만 존재해야 모든 컴퓨터들이 연결될 수 있는 조건이 완성될 것이다.
여기서 주의해야할 점이 한번더 parent값을 갱신해야된다는 점이다.

왜냐하면 경로압축이 끝까지 안된 노드들이 있을 수 있기 때문에 반드시 한번더 find_parent를 돌려주어야 한다.