김호쭈
DevForYou
김호쭈
전체 방문자
오늘
어제
  • 분류 전체보기 (321)
    • • 데이터베이스(DB) (9)
      • __SQL__ (9)
    • •알고리즘(Algorithm ) (117)
      • 문제풀이 (99)
      • 스터디 (14)
      • 알고리즘 팁 (4)
    • •Compter Science (57)
      • Operating System (25)
      • Computer Network (1)
      • Computer Vision (16)
      • Artificial Intelligence (14)
      • Software Technology (1)
    • • 독서 (36)
      • Design Pattern (24)
      • 객체지향의 사실과 오해 (1)
      • Object Oriented Software En.. (11)
    • • 개발 (26)
      • React (3)
      • node.js (6)
      • Django (11)
      • Spring boot (6)
    • • 개발Tip (4)
      • GitHub (0)
    • •프로젝트 (2)
      • 물물 (2)
    • •App (54)
      • 안드로이드 with Kotlin (50)
      • 코틀린(Kotiln) (4)
    • •회고 (8)
    • •취준일기 (3)
    • • 기타 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 원격저장소
  • Remote저장소
  • 깃허브데스크탑
  • local저장소
  • ㄱ
  • KMU_WINK
  • GitHubDesktop
  • 로컬저장소

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
김호쭈

DevForYou

•알고리즘(Algorithm )/문제풀이

[백준1647&파이썬] 크루스칼 알고리즘을 이용한다면 최소신장트리(MST)를 찾을 수 있다.

2023. 4. 26. 00:34

# 문제

백준 1647 도시분할 계획 파이썬 풀이

 

 

1647번: 도시 분할 계획

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

www.acmicpc.net

# 코드

'''
  - 마을을 두개로 분리해야한다.
    - 마을을 두개로 분리할때, MST로 만들고 간선 하나를 떼버리면 마을이 두개로 분리된다.
    - 그렇다면 가장 큰 값을 가진 간선을 떼버리면 되지 않을까
'''
import sys
from heapq import *

N, M = map(int, sys.stdin.readline().split())  # N : 집의 개수, M : 길의 개수
edges = list()

parent = [i for i in range(N + 1)]
rank = [1] * (N + 1)


def find(node):
  if parent[node] == node:
    return node
  parent[node] = find(parent[node])
  return parent[node]


def union(nodeA, nodeB):
  a = find(nodeA)
  b = find(nodeB)

  if a == b:  # 아무것도 할 필요가 없다.
    return

  if rank[a] < rank[b]:
    parent[a] = b
  else:
    parent[b] = a
    if rank[a] == rank[b]:  # 같으면
      rank[a] += 1


for _ in range(M):
  a, b, c = map(int, sys.stdin.readline().split())
  # print(c,a,b)
  heappush(edges,(c, a, b))

# 크루스칼을 통해서 MST를 구한다
cnt = 0
result = 0
mmax = 0
while True:
  if cnt == N - 1 :  # 종료조건
    break
  cur = heappop(edges)  # ( weight, a , b  )
  # print(cur)
  if find(cur[1]) != find(cur[2]):  # 같은 집합이 아니라면
    # print("👆👆pop👆👆")
    union(cur[1], cur[2])
    mmax = max(mmax,cur[0])
    result += cur[0]
    cnt += 1

# print(parent)
print(result-mmax)

# 풀이

  • 문제에서 요구하는 출력은 마을을 두개로 분리된 상태에서의 간선들의 총합이 가장 작을때이다.
  • 크루스칼을 이용해서 현재 연결된 마을의 MST를 구한다. 그리고 거기서 가장 큰 간선을 빼버린다면, 간선의 합이 가장 작은 경우일 것이다.
  • 크루스칼 알고리즘은 MST(최소신장트리)를 구할 수 있다. 크루스칼알고리즘은 가장 작은 간선(edge)들을 하나씩 뽑아서 선택하되 그 간선이 선택됐을때 사이클이 생기면 안된다. 그렇기 때문에 사이클 여부는 union-find를 사용하여 최적화 한다.
  • 크루스칼 알고리즘의 간선을 pop하는 과정을 최적화 하기 위해서 최소힙을 사용했다. 힙을 사용하는 경우 시간복잡도는 O(m*logn)이고 퀵소트를 사용하는 경우에는 O(m*logm)이기 때문에 힙이 더 빠르다고 한다.
  • union-find에서 find시 부모노드와 바로 연결시키는 것과 더불어 rank를 사용하는것을 손에 익게 하자.
저작자표시 (새창열림)

'•알고리즘(Algorithm ) > 문제풀이' 카테고리의 다른 글

[백준16236&파이썬] BFS을 작은단위로 쪼개 생각하자. 종료조건과 탐색조건을 잘 생각하자.  (0) 2023.04.26
[백준6497&파이썬] 크루스칼은 최소신장트리를 구할 수 있다.  (0) 2023.04.26
[백준1956&파이썬] 플로이드-와샬을 이용해 왕복 최단거리를 찾아보자  (0) 2023.04.25
[백준2610&파이썬] 플로이드-와샬과 유니온파인드를 함께 이용해보자.  (1) 2023.04.25
[백준1613&파이썬] 플로이드 와샬 알고리즘은 모든 노드로부터 특정노드까지의 연결여부를 알 수 있다.  (0) 2023.04.25
    '•알고리즘(Algorithm )/문제풀이' 카테고리의 다른 글
    • [백준16236&파이썬] BFS을 작은단위로 쪼개 생각하자. 종료조건과 탐색조건을 잘 생각하자.
    • [백준6497&파이썬] 크루스칼은 최소신장트리를 구할 수 있다.
    • [백준1956&파이썬] 플로이드-와샬을 이용해 왕복 최단거리를 찾아보자
    • [백준2610&파이썬] 플로이드-와샬과 유니온파인드를 함께 이용해보자.
    김호쭈
    김호쭈
    공부하고 정리하고 기록하기

    티스토리툴바