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

최소 신장 트리, MST(Minimum Spanning Tree) #37

Closed
Taehyeon-Kim opened this issue Feb 6, 2023 · 1 comment
Closed

최소 신장 트리, MST(Minimum Spanning Tree) #37

Taehyeon-Kim opened this issue Feb 6, 2023 · 1 comment
Assignees
Labels

Comments

@Taehyeon-Kim
Copy link
Owner

Taehyeon-Kim commented Feb 6, 2023

유니온-파인드(Union-find) 자료구조

  • 크루스칼 알고리즘 구현 시 사용
  • 그래프 사이클 탐지 시 사용

find 연산

func findParent(_ x: Int) -> Int {
  if p[x] == x { return x }
  p[x] = findParent(p[x])
  return p[x]
}

union 연산

func union(_ u: Int, _ v: Int) -> Bool {
  let u = findParent(u)
  let v = findParent(v)
  if u == v { return false }
  if u < v { p[v] = u }
  else { p[u] = v }
  return true
}
  • 부모 노드, 루트 노드가 같다는 것은 union x, 즉 합칠 수 없다는 의미(사이클이 생긴다는 의미)

최초 부모 노드 초기화

var p = [Int]()
for i in 0..<n+1 {
  p.append(i)
}

크루스칼(Kruskcal) 알고리즘

  • 간선의 비용이 작은 것부터 선택해나가야 하기 때문에 최초에 정렬을 한 번 해주고 시작한다. 이 때, 튜플 자료구조를 사용하게 된다.
  • 간선을 V-1개 선택할때까지 반복하다가, V-1개가 되는 순간 종료한다.
func kruskcal() -> Int {
  var (ret, edges) = (0, 0)

  for (cost, u, v) in tuple {
    // 합칠 수 있다 = 사이클 x = 서로소
    if union(u, v) {
      ret += cost
      edges += 1
      // vertex - 1 까지 반복 가능
      if edges == n - 1 {
        return ret
      }
    }
  }
  return -1
}

전체코드

func input() -> (p: [Int], tuple: [(Int, Int, Int)], v: Int, e: Int) {
    let ve = readLine()!.split(separator: " ").compactMap {Int(String($0))}
    let (v, e) = (ve[0], ve[1])

    // 1) 튜플을 만든다.
    // - (가중치, 정점1, 정점2)
    var tuple = [(Int, Int, Int)]()
    for _ in 0..<e {
        let line = readLine()!.split(separator: " ").compactMap {Int(String($0))}
        let (a, b, c) = (line[0], line[1], line[2])
        tuple.append((c, a, b))
    }

    // 2) 튜플을 가중치 기준으로 오름차순 정렬한다.
    // - 작은 값부터 더해나가기 위함
    tuple = tuple.sorted(by: { $0.0 < $1.0 })
  
    // 3) 부모 노드 배열 초기화
    var p = [Int]()
    for i in 0..<v+1 {
        p.append(i)
    }
    
    return (p, tuple, v, e)
}

func kruskcal() -> Int {
    var (p, tuple, V, _) = input()

    // 4) find 연산
    func findParent(_ x: Int) -> Int {
        if p[x] == x { return x }
        p[x] = findParent(p[x])
        return p[x]
    }
    
    // 5) union 연산
    // - Bool 타입을 리턴해서 사이클 여부를 판단한다.
    func union(_ u: Int, _ v: Int) -> Bool {
        let u = findParent(u)
        let v = findParent(v)
        
        if u == v { return false }
        if u < v { p[v] = u }
        else { p[u] = v }
        return true
    }
    
    // 6) 가중치 합, 간선의 개수 -> ans, cnt
    // cnt(간선의 개수)가 (정점의 개수 - 1) 일 때 연산을 마친다.
    var (ans, cnt) = (0, 0)
    for (cost, u, v) in tuple {
        if union(u, v) {
            cnt += 1
            ans += cost
            if cnt == V - 1 {
                return ans
            }
        }
    }
    return ans
}

print(kruskcal())
@Taehyeon-Kim
Copy link
Owner Author

Taehyeon-Kim commented Feb 6, 2023

  • boj 1197 최소 스패닝 트리 (기본꼴, 연습문제)
  • boj 1922 네트워크 연결

@Taehyeon-Kim Taehyeon-Kim self-assigned this Feb 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant