김호쭈
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저장소
  • GitHubDesktop
  • 원격저장소
  • ㄱ
  • KMU_WINK
  • 로컬저장소
  • 깃허브데스크탑

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
김호쭈

DevForYou

[백준2610&파이썬] 플로이드-와샬과 유니온파인드를 함께 이용해보자.
•알고리즘(Algorithm )/문제풀이

[백준2610&파이썬] 플로이드-와샬과 유니온파인드를 함께 이용해보자.

2023. 4. 25. 18:55

# 문제

백준 2610 회의준비 파이썬 풀이

 

2610번: 회의준비

첫째 중에 회의에 참석하는 사람의 수 N이 주어진다. 참석자들은 1부터 N까지의 자연수로 표현되며 회의에 참석하는 인원은 100 이하이다. 둘째 줄에는 서로 알고 있는 관계의 수 M이 주어진다. 이

www.acmicpc.net

# 코드

'''
  - 플로이드-와샬을 이용해서 다른 노드까지의 방문의 합이 최소인 노드를 대표로노드로 선정한다
    - 근데 같은 집단(위원회)인건 어떻게 구별해야하나?
    - 보통 집단을 찾는건 BFS를 활용하기는 하는데.. OR UNION - FIND
    - 일단 못가는 곳은 INF로 표현 되긴 함
    - 유니온 파인드로 구분하는 전처리 과정을 거치자
      https://eun-jeong.tistory.com/15
'''

import sys
from collections import defaultdict

N = int(sys.stdin.readline()) # 참석 하는 사람의 수
M = int(sys.stdin.readline()) # 서로 알고 있는 사람

distance = [[float('inf')] * (N+1) for _ in range(N+1)]

# union-find로 집합여부를 먼저 판단하자
parent = [i for i in range(N+1)]
rank = [1 for i in range(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 rank[a] < rank[b] :
    parent[a] = b
  else :
    parent[b] = a
    if rank[a] == rank[b] : # Rank가 같다면, b를 a에 붙였기 때문에 a의 랭크를 1 올려줘야함 ( 루트 )
      rank[a] += 1



for _ in range(M) :
  a,b = map(int,sys.stdin.readline().split())
  # 양방향 관계
  distance[a][b] = 1
  distance[b][a] = 1
  union(a,b) # 유니온 파인드 수행



for i in range(N+1) :
  distance[i][i] = 0 # 시작 노드 초기화


for pivot in range(1, N+1) :
  for start in range(1, N+1) :
    for end in range(1, N+1) :
      distance[start][end] = min(distance[start][pivot] + distance[pivot][end], distance[start][end])





result = defaultdict(lambda : (float('inf'), -1)) # 초기값을 inf로 하기 위해서
for index,item in enumerate(parent[1:]) :
  index += 1
  item = find(item) # parent에서 꺼낸 노드의 값이 항상 부모는 아니기 때문에 부모 노드를 찾아야한다.

  # 최대값 찾기
  # 찾은 최대값과 현재 캐싱된 값 비교
  # 찾은 최대값이 더 작다면 업데이트

  mmax = -1
  for i in distance[index][1:] :
    if i == float('inf') :
      continue
    if mmax < i :
      mmax = i # 최대값 찾기

  if mmax < result[item][0] :
    result[item] = (mmax, index)


# print(parent)
# print(result)
# for i in range(1,N+1) :
#   print(*distance[i][1:])
# print()

print(len(result))
for item in sorted(list(result.values()), key = lambda x : x[1] ) :
  print(item[1])

# 풀이

## 주의사항

아래와 같은 사항들을 생각하지 못해서 다 풀어놓고 정답까지 많은 시간을 소비해버렸다.

  • 모든 참석자들의 의사전달 시간의 총합중의 최소값을 구하는 것이 아니다. 모든 참석자들의 의사전달시간중 최대값을 구하고 그 최대값이 가장 작은 것을 구해야한다.
  • UNION-FIND를 사용했으면, 그로 인해 얻어낸 PARENT 배열을 그대로 사용한다면 그건 그 노드의 부모노드가 아니다. PARENT안에 들어있는 값을 통해 find를 해야지 부모의 노드가 나온다. ( 즉 자기가 속한 집단 )

## 접근방법

  • 이 문제를 해결하기 위해서 아래와 같이 두가지 방법을 어떻게 수행해야할지 고민했다.
    • 각 노드에서 시작하는 의사전달의 최대값을 어떻게 구해낼 것인가? 이것은 모든 노드로부터 시작하는 것을 찾아봐야한다.
    • 어떤 집단(위원회)에 속하는지 그룹핑을 어떻게 할 것인가?

 

  • 첫번째는, 플로이드-워셜을 사용해서 모든노드에서 시작하여 모든 노드까지의 도착하는 거리들을 찾아내고, 해당 거리중 최대값들을 찾아내는것으로 어렵지 않게 해결했다.
  • 두번째는, 각 집단을 어떻게 그룹핑 할 것인가에 대한 고민인데, 이걸 플로이드-와샬을 통해서 한번해 해보려고 했는데 좋은 방법이 생각나지 않았고, BFS나 Union-find로 해결하고자했다. BFS보단 Union-find가 빠를거 같았기 때문에 해당 풀이 방법을 선택했다.
  • Union-Find는 많이 사용해봤지만, rank를 이용한 최적화는 처음 사용해봤다. 보통 root를 find시에 초기화 해주는거 까지 해줬었다. rank를 이용할때는, a,b의 rank를 비교하고 rank가 큰 쪽에 작은거를 붙여주는 식으로 활용한다. 그렇다면 rank의 길이는 큰쪽의 상태가 되기 때문에 따로 변화되지 않는다. 
  • 만일 Rank가 같다면 rank의 크기를 1올려줘야 한다. 이 원리는 간단하다. 밑으로 들어가기 때문이다.

 

# 참고

 

[알고리즘] 유니온 파인드 : Union-Find (Disjoint Set)

Union-find? 그래프 알고리즘의 일종으로써, 상호 배타적 집합(Disjoint Set)이라고도 한다. 여러 노드가 존재할 때, 어떤 두 개의 노드를 같은 집합으로 묶어주고, 다시 어떤 두 노드가 같은 집합에 있

eun-jeong.tistory.com

저작자표시 (새창열림)

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

[백준1647&파이썬] 크루스칼 알고리즘을 이용한다면 최소신장트리(MST)를 찾을 수 있다.  (0) 2023.04.26
[백준1956&파이썬] 플로이드-와샬을 이용해 왕복 최단거리를 찾아보자  (0) 2023.04.25
[백준1613&파이썬] 플로이드 와샬 알고리즘은 모든 노드로부터 특정노드까지의 연결여부를 알 수 있다.  (0) 2023.04.25
[백준11404&파이썬] 플로이드-와샬을 이용해서 모든정점에서부터 모든정점까지의 최단거리 구하기  (0) 2023.04.25
[백준1162&파이썬] 다익스트라에서 distance를 여러가지로 갈래로 분리시켜야 할때  (1) 2023.04.23
    '•알고리즘(Algorithm )/문제풀이' 카테고리의 다른 글
    • [백준1647&파이썬] 크루스칼 알고리즘을 이용한다면 최소신장트리(MST)를 찾을 수 있다.
    • [백준1956&파이썬] 플로이드-와샬을 이용해 왕복 최단거리를 찾아보자
    • [백준1613&파이썬] 플로이드 와샬 알고리즘은 모든 노드로부터 특정노드까지의 연결여부를 알 수 있다.
    • [백준11404&파이썬] 플로이드-와샬을 이용해서 모든정점에서부터 모든정점까지의 최단거리 구하기
    김호쭈
    김호쭈
    공부하고 정리하고 기록하기

    티스토리툴바