[BOJ알고리즘, C++]#13418_학교 탐방하기, 최소 신장 트리, MST, 크루스칼

2024. 6. 21. 19:18· 문제 풀이/BOJ 문제 풀이
목차
  1. #1. 문제
  2. #2. 풀이
  3. 1. 최소 신장 트리
  4. 2. 크루스칼 알고리즘
  5. 3. 최악? 내림차순 정렬, 최선? 오름차순 정렬
  6. #3. 코드

 

#1. 문제

https://www.acmicpc.net/problem/13418

 


 

#2. 풀이

 

1. 최소 신장 트리

 

[자료구조]#6_그래프

#0. 개념 1. 그래프?[정의] : 그래프는 노드와 간선들의 집합으로 이루어진 비 선형 자료구조입니다. 그래프의 노드들은 간선을 통해 연결되어 일종의 네트워크를 형성합니다. 그래프는 노드와

webddevys.tistory.com

신장 트리는 그래프의 모든 정점을 최소한의 간선으로 순환 구조 없이 연결하는 부분 그래프를 의미합니다. 따라서, 최소 신장 트리는 가중치 그래프에서 간선들의 합이 최소가 되는 신장 트리입니다. 최소 신장 트리 알고리즘으로 크루스칼 알고리즘, 프림 알고리즘, 솔린 알고리즘이 있습니다. 

 

2. 크루스칼 알고리즘

 

[자료구조]#6_그래프

#0. 개념 1. 그래프?[정의] : 그래프는 노드와 간선들의 집합으로 이루어진 비 선형 자료구조입니다. 그래프의 노드들은 간선을 통해 연결되어 일종의 네트워크를 형성합니다. 그래프는 노드와

webddevys.tistory.com

크루스칼 알고리즘은 최소 신장 트리 알고리즘 중 하나로 무방향 그래프의 각 간선들을 가중치 기준 오름차순 정렬하여, 최소 가중치를 갖는 간선을 선택하며 최소 신장 트리를 구성하는 알고리즘입니다. 일반적으로, 크루스칼 알고리즘은 간선 목록의 오름차순 정렬과 Union-Find 연산을 통해 구현됩니다. 크루스칼 알고리즘의 시간 복잡도는 최악의 경우 O(e log n)입니다.(e = 간선의 수, n = 정점의 수)

 

3. 최악? 내림차순 정렬, 최선? 오름차순 정렬

  1. 먼저, 간선 목록을 구성할 때 오르막 길은 +1의 가중치를, 내리막 길은 0의 가중치를 갖도록 합니다.
  2. 최악의 경우는 간선 목록을 내림 차순 정렬한 뒤 크루스칼을 수행하고, 최선의 경우는 간선 목록을 오름 차순 정렬한 뒤 크루스칼을 수행합니다.
  3. 위 두 번의 크루스칼 수행의 결과 값을 빼주어 정답을 출력합니다.

 


 

#3. 코드

/*
    @문제: 피로도가 최대가 되는 경로 - 피로도가 최소가 되는 경로 구하기
    @설명:
        1. 간선목록 구성 시 오르막은 가중치를 1로, 내리막은 가중치를 0으로 변경
        2. 최대 신장 트리는 가중치 기준 내림차순 정렬 후 Kruskal 수행
        3. 최소 신장 트리는 가중치 기준 오름차순 정렬 후 Kruskal 수행
        4. 위 두 결과 값의 차이를 결과로 출력
*/

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;

#define MAX 1001

// 간선 구조체 정의
struct Edge{
    int u,v,w;
    const bool operator<(const Edge& other)
    {
        return w<other.w;
    }

    const bool operator>(const Edge& other)
    {
        return w>other.w;
    }
};

int N, M, minST, maxST, res;
vector<Edge> edges;

int flip(int x)
{
    return x ^= 1;
}

// Union-Find 연산
int Find(int x, vector<int>& parent)
{
    if(parent[x] != x)
    {
        return parent[x] = Find(parent[x], parent);
    }
    else return x;
}

void Union(int rootX, int rootY, vector<int>& parent, vector<int>& ranks)
{
    if(ranks[rootX] > ranks[rootY])
    {
        parent[rootY] = rootX;
    }
    else if(ranks[rootY] > ranks[rootX])
    {
        parent[rootX] = rootY;
    }
    else{
        parent[rootY] = rootX;
        ranks[rootY]++;
    }
}

// 크루스칼 : 간선 목록 정렬에 대하여 isWorst가 참이면 가중치 기준 내림차순 정렬, 거짓이면 오름차순 정렬
int kruskal(vector<Edge> edges, bool isWorst)
{
    vector<int> parent(N+1);
    vector<int> ranks(N+1, 0);
    int fatigueVal=0;

    // 부모 목록 초기화
    for(int i=1; i<=N; ++i)
        parent[i] = i;

    // 간선 목록의 정렬 방식 선택
    if(isWorst) sort(begin(edges), end(edges), [](const Edge& a, const Edge& b){
        return a.w > b.w;
    });
    else sort(begin(edges), end(edges));

    for(const auto edge : edges)
    {
        int rootX = Find(edge.u, parent);
        int rootY = Find(edge.v, parent);

        if(rootX != rootY)
        {
            fatigueVal += edge.w;
            Union(rootX, rootY, parent, ranks);
        }
    }

    return pow(fatigueVal,2);
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> N >> M;

    for(int i=0; i<=M; ++i)
    {
        int u,v,w;
        cin >> u >> v >> w;
        // 간선 목록 구성, 편의상 오르막은 0->1로 변경 + 내리막은 1->0으로 변경
        edges.push_back(Edge({u,v,flip(w)}));
    }

    //Reverse Kruskal (최대 스패닝 트리)
    res += kruskal(edges, true);
    //Kruskal (최소 스패닝 트리)
    res -= kruskal(edges, false);

    cout << res;

    return 0;
}

 


 

 

 

 

저작자표시 (새창열림)

'문제 풀이 > BOJ 문제 풀이' 카테고리의 다른 글

[BOJ알고리즘, C++]#2512_예산, 이분 탐색, Binary Search  (0) 2024.06.21
[BOJ알고리즘, C++]#1613_역사, 플로이드-워셜, 최단 경로, 길 찾기, 그래프 순환 여부  (0) 2024.06.21
[BOJ알고리즘, C++]#5670_휴대폰 자판, Trie 자료구조, 트리  (0) 2024.06.21
[BOJ알고리즘, C++]#1735_분수 합, 유클리드 호제법, 최대 공약수, 최소 공배수, gcd, lcm  (0) 2024.06.19
[BOJ알고리즘, C++]#1446_지름길, 최단 경로, 길 찾기, 다익스트라  (0) 2024.06.19
  1. #1. 문제
  2. #2. 풀이
  3. 1. 최소 신장 트리
  4. 2. 크루스칼 알고리즘
  5. 3. 최악? 내림차순 정렬, 최선? 오름차순 정렬
  6. #3. 코드
'문제 풀이/BOJ 문제 풀이' 카테고리의 다른 글
  • [BOJ알고리즘, C++]#2512_예산, 이분 탐색, Binary Search
  • [BOJ알고리즘, C++]#1613_역사, 플로이드-워셜, 최단 경로, 길 찾기, 그래프 순환 여부
  • [BOJ알고리즘, C++]#5670_휴대폰 자판, Trie 자료구조, 트리
  • [BOJ알고리즘, C++]#1735_분수 합, 유클리드 호제법, 최대 공약수, 최소 공배수, gcd, lcm
Hardii2
Hardii2
개발 블로그Hardii2 님의 블로그입니다.
Hardii2
개발 블로그
Hardii2
전체
오늘
어제
  • 분류 전체보기
    • 알고리즘
    • 웹 개발
      • Node.js
      • React
    • 게임개발
      • DirectX12
      • 관련 지식
      • Unreal C++
      • Unreal 블루프린트
    • 언어
      • Effective C++
      • Basic C++
      • 디자인 패턴
      • 자료구조
      • 기술 질문
    • 문제 풀이
      • BOJ 문제 풀이
      • Programmers 문제 풀이
      • geeksForgeeks 문제 풀이
    • 수학
      • 확률과 통계
      • 게임수학
    • 개인프로젝트
    • 그룹프로젝트
      • PM
      • Dev
    • Github

블로그 메뉴

  • 홈
  • 글쓰기

공지사항

인기 글

태그

  • Effective C++
  • unreal
  • 개발
  • 트리
  • 기술 질문
  • programmers
  • 최단 경로
  • 우선순위 큐
  • BFS
  • 그래프
  • dfs
  • Unreal Blueprint
  • C++
  • DP
  • stl
  • 정렬
  • set
  • 알고리즘
  • BOJ
  • 디자인 패턴

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
Hardii2
[BOJ알고리즘, C++]#13418_학교 탐방하기, 최소 신장 트리, MST, 크루스칼
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.