Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

24-jung0115 #187

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open

24-jung0115 #187

wants to merge 25 commits into from

Conversation

jung0115
Copy link
Member

@jung0115 jung0115 commented Nov 9, 2024

➡️ 풀이 코드

🔗 문제 링크

프로그래머스 | 그리디 알고리즘 - 섬 연결하기(Lv.3)

n개의 섬 사이에 다리를 건설하는 비용(costs)이 주어질 때, 최소의 비용으로 모든 섬이 서로 통행 가능하도록 만들 때 필요한 최소 비용을 return 하도록 solution을 완성하세요.

다리를 여러 번 건너더라도, 도달할 수만 있으면 통행 가능하다고 봅니다. 예를 들어 A 섬과 B 섬 사이에 다리가 있고, B 섬과 C 섬 사이에 다리가 있으면 A 섬과 C 섬은 서로 통행 가능합니다.

[ 제한사항 ]

  • 섬의 개수 n은 1 이상 100 이하입니다.
  • costs의 길이는 ((n-1) * n) / 2이하입니다.
  • 임의의 i에 대해, costs[i][0] 와 costs[i] [1]에는 다리가 연결되는 두 섬의 번호가 들어있고, costs[i] [2]에는 이 두 섬을 연결하는 다리를 건설할 때 드는 비용입니다.
  • 같은 연결은 두 번 주어지지 않습니다. 또한 순서가 바뀌더라도 같은 연결로 봅니다. 즉 0과 1 사이를 연결하는 비용이 주어졌을 때, 1과 0의 비용이 주어지지 않습니다.
  • 모든 섬 사이의 다리 건설 비용이 주어지지 않습니다. 이 경우, 두 섬 사이의 건설이 불가능한 것으로 봅니다.
  • 연결할 수 없는 섬은 주어지지 않습니다.

✔️ 소요된 시간

45분

✨ 수도 코드

Prim 알고리즘을 활용해서 그리디하게 풀어냈습니다!

우선 costs 배열의 내용을 보고, 건설 가능한 다리를 그래프로 저장해줬습니다. 그래프에는 각 섬마다 연결된 섬과 비용이 저장됩니다

그리고 0번 섬부터 시작해서 아래의 과정을 따릅니다

  1. connect set은 연결이 완료된 섬을 관리. connect에 0 추가
  2. edges 리스트에 0번 섬과 연결된 모든 간선을 추가하고, 비용 순서대로 정렬
  3. edges 리스트에서 가장 비용이 적은 간선 선택
    3-1. 선택한 간선의 도착지가 이미 connect에 있을 경우, 이미 연결된 섬이므로 패스
    3-2. 그렇지 않을 경우 해당 간선을 연결하고, 1번 과정으로 돌아가서 도착점에 있는 섬에서 연결된 최적 간선 찾기

모든 섬이 연결되면 위 과정을 종료하고, 누적된 총 비용을 반환하면 됩니다!

최종 코드

def solution(n, costs):
  answer = 0
  
  graph = [[] for _ in range(n)]
  for cost in costs:
    u, v, w = cost
    graph[u].append((w, v))
    graph[v].append((w, u))

  connect = set() # 연결된 섬
  connect.add(0)
  
  edges = graph[0] # 다리
  edges.sort()          # 비용을 기준으로 오름차순 정렬
  
  while len(connect) < n:
    w, v = edges.pop(0)
    
    # 이미 연결된 섬
    if v in connect:
      continue
    
    # 다리 건설
    answer += w
    connect.add(v)
    
    for edge in graph[v]:
      if edge[1] not in connect:
        edges.append(edge)
    
    edges.sort()
  
  return answer

📚 새롭게 알게된 내용

Copy link
Member

@janghw0126 janghw0126 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와우 프림알고리즘 제대로 까먹고 있었는데 정미님 덕분에 다시 상기되었습니다!
덕분에 개념부터 활용까지 확실히 알 수 있었네요🥹

저도 정미님의 코드를 따라가보면서 프림 알고리즘의 초점에 맞춰 하나의 정점을 정하고 인접 정점 중 가중치가 낮은 간선을 계속 골라가는 방법으로 구현하였습니다.

def solution(n, costs):
    answer = 0
    
    # 그래프를 초기화함
    graph = [[] for _ in range(n)]
    for u, v, cost in costs:
        graph[u].append((cost, v))
        graph[v].append((cost, u))

    # 연결된 섬 집합과 초기 다리 후보 리스트를 선언함
    connected_islands = set([0])
    bridge_candidates = graph[0]
    # 비용 오름차순으로 정렬
    bridge_candidates.sort() 

    while len(connected_islands) < n:
        cost, next_island = bridge_candidates.pop(0)
        
        # 이미 연결된 섬일 경우 스킵함
        if next_island in connected_islands:
            continue
        
        # 다리를 건설하고 섬을 연결함
        answer += cost
        connected_islands.add(next_island)

        # 새로 연결된 섬의 다리 후보를 추가함
        for new_bridge in graph[next_island]:
            if new_bridge[1] not in connected_islands:
                bridge_candidates.append(new_bridge)
        
        # 항상 최소 비용의 다리부터 선택할 수 있도록 정렬함
        bridge_candidates.sort()

    return answer

다른 분들의 코드를 보니까 하나의 정점을 정하는 것이 아닌 임의의 정점에서 시작하여 선택해나가는 크루스칼 알고리즘을 이용한 풀이도 있었습니다!
참고하시면 좋을 것 같아요😚👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants