파이썬 코딩테스트/해커랭크

HackerRank / Kruskal (MST) : Really Special Subtree / Python

S.T.Lee 2021. 12. 11. 22:44

 

https://www.hackerrank.com/challenges/kruskalmstrsub/problem?isFullScreen=true

 

Kruskal (MST): Really Special Subtree | HackerRank

Learn to use the Kruskal's algorithm !

www.hackerrank.com

참조

https://techblog-history-younghunjo1.tistory.com/262

 

 

크루스칼 알고리즘에 들어가기 앞서 신장 트리, 최소 신장 트리에 대해 알아야 한다.

위의 블로그에 잘 정리가 되어있지만 짧게 설명을 하자면

1) 신장 트리 - 하나의 그래프가 있을 때, 모든 노드를 포함하면서 즉, 모든 노드들 간에 서로 연결은 되어있지만 사이클이 존재하지 않는 '부분' 그래프이다.

2) 최소 신장 트리 - 간선 비용이 존재할 때 사이클이 형성되지 않으며 간선 비용이 최소가 되는 알고리즘이다.

 

문제 특이점

위의 문제의 경우 크루스칼 알고리즘이나 간선 비용이 같을시 '출발 노드 + 도착 노드 + 간선 비용'이 작은 edge를 사용하라고 나와있다.

 

문제 접근

1) weight에 대해 edge 정렬

2) 정렬된 리스트에 대해 sum값으로 부분 정렬

3) Union_Find를 통한 문제 해결

 

#!/bin/python3

import math
import os
import random
import re
import sys

def kruskals(g_nodes, g_from, g_to, g_weight):
    sort_list = [] # 정렬할 리스트 생성
    length = 0
    for i in range(len(g_from)): # weight에 대해 정렬
        g_sum = g_from[i] + g_to[i] + g_weight[i]
        sort_list.append([g_from[i],g_to[i],g_weight[i],g_sum])
    sort_list.sort(key = lambda x:x[2])
    
    for s in range(len(sort_list)-1): # 정렬된 리스트에서 sum값에 대해 부분 정렬
        s1 = sort_list[s]
        s2 = sort_list[s+1]
        if (s1[2] == s2[2] & s1[3]>s2[3]):
            tmp = sort_list[s+1]
            sort_list[s+1] = sort_list[s]
            sort_list[s] = tmp
        else:
            pass        
    
    parent = [0 for i in range(g_nodes + 1)] #원래는 -1이나 해당 문제는 노드가 1부터 시작하기에 문제 없다
    for i in range(1, g_nodes+1):
        parent[i] = i
    def find_parent(parent, x): # 부모 노드 확인
        if parent[x] != x:
            parent[x] = find_parent(parent, parent[x])
        return parent[x]

    def union_parent(parent, a, b): # 부모 노드 변경
        a = find_parent(parent, a)
        b = find_parent(parent, b)
        if a < b:
            parent[b] = a
        else:
            parent[a] = b

    for i in range(len(sort_list)): # 부모 노드가 다를 때(=사이클이 생성되지 않을때) union 연산 실행
        if find_parent(parent, sort_list[i][0]) != find_parent(parent, sort_list[i][1]):
            union_parent(parent, sort_list[i][0], sort_list[i][1])
            length+=sort_list[i][2]
    
    return length

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    g_nodes, g_edges = map(int, input().rstrip().split())
    # print(g_edges)
    g_from = [0] * g_edges
    g_to = [0] * g_edges
    g_weight = [0] * g_edges

    for i in range(g_edges):
        g_from[i], g_to[i], g_weight[i] = map(int, input().rstrip().split())
    
    res = kruskals(g_nodes, g_from, g_to, g_weight)
    
    # Write your code here.
    fptr.write(str(res)+'\n')
    
    fptr.close()