코딩테스트/프로그래머스

[99클럽/코딩테스트 챌린지/C++] 전력망을 둘로 나누기 문제 해결

유니얼 2024. 11. 21. 05:39
728x90

문제 링크:

https://school.programmers.co.kr/learn/courses/30/lessons/86971

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

문제 요약

이 문제는 주어진 송전탑과 전선 정보에서, 전선 하나를 끊어 두 전력망으로 나누었을 때 송전탑 개수의 차이가 최소가 되도록 하는 것입니다.

문제의 주요 조건:

  1. 입력으로 주어진 송전탑 네트워크는 항상 트리 구조입니다.
  2. 전선 하나를 끊으면 두 전력망으로 분리됩니다.
  3. 송전탑의 개수를 비교해 그 차이를 최소화해야 합니다.

문제 해결 접근법

1. 그래프를 인접 리스트로 표현

  • 전선으로 연결된 송전탑 관계를 그래프의 형태로 나타냅니다.
  • 인접 리스트를 사용하여 각 송전탑에 연결된 다른 송전탑의 정보를 저장합니다.

2. 전선 하나를 끊고 네트워크를 분리

  • 모든 전선을 한 번씩 끊고, 두 네트워크의 송전탑 개수를 계산합니다.
  • 전선을 끊는 것은 인접 리스트에서 해당 연결을 제거하는 것으로 구현됩니다.

3. BFS를 이용한 송전탑 개수 계산

  • 분리된 네트워크에서 하나의 송전탑을 시작으로 BFS를 사용해 연결된 송전탑의 개수를 계산합니다.
  • 전체 송전탑 개수에서 BFS로 계산된 송전탑 개수를 빼면 다른 네트워크의 송전탑 개수를 구할 수 있습니다.

4. 송전탑 개수 차이의 최소값 찾기

  • 각 전선을 끊었을 때 두 네트워크의 송전탑 개수 차이를 계산하여 최소값을 갱신합니다.

코드 설명

#include <iostream>
#include <vector>
#include <math.h>
#include <queue>
#include <algorithm>
using namespace std;

vector<int> visited;
vector<vector<int>> graph;

// BFS를 이용해 네트워크의 송전탑 개수를 계산
int bfs(int start) {
    int count = 0;
    queue<int> q;
    q.push(start);
    visited[start] = 1;
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        count++;
        for (int nei : graph[cur]) {
            if (visited[nei]) continue;
            q.push(nei);
            visited[nei] = 1;
        }
    }
    return count;
}

// 주어진 문제 해결
int solution(int n, vector<vector<int>> wires) {
    int answer = n;
    graph = vector<vector<int>>(n + 1);

    // 그래프 생성 (인접 리스트)
    for (const auto& wire : wires) {
        int from = wire[0];
        int to = wire[1];
        graph[from].push_back(to);
        graph[to].push_back(from);
    }

    // 각 전선을 끊고 네트워크를 분리
    for (const auto& wire : wires) {
        visited = vector<int>(n + 1);

        // 전선을 끊는다
        int from = wire[0];
        int to = wire[1];
        graph[from].erase(remove(graph[from].begin(), graph[from].end(), to), graph[from].end());
        graph[to].erase(remove(graph[to].begin(), graph[to].end(), from), graph[to].end());

        // BFS를 통해 송전탑 개수를 계산
        int a = bfs(from);
        int b = n - a;

        // 두 네트워크 송전탑 개수 차이의 최소값 갱신
        answer = min(answer, abs(a - b));

        // 전선을 복구한다 (Backtracking)
        graph[from].push_back(to);
        graph[to].push_back(from);
    }

    return answer;
}

 

배운 점

1, 인접 리스트를 활용한 그래프 구현

  • 처음에는 전력망 네트워크를 처리하기 위해 인접 리스트를 사용하는 것을 떠올리지 못했습니다.
  • 트리 구조와 그래프의 관계를 이해하고, 인접 리스트를 활용해 그래프를 구현하는 방법을 배웠습니다.

2, BFS를 활용한 연결된 노드 탐색

  • BFS를 사용해 연결된 송전탑 개수를 계산하는 방법을 익혔습니다.
  • queue를 활용하여 탐색의 효율성을 높이고, 방문 여부를 관리하기 위해 visited 배열을 사용했습니다.

3, 그래프 복구(Backtracking)

  • 전선을 끊은 후 탐색이 끝나면 원래 상태로 복구하는 작업(Backtracking)이 필요했습니다.
  • erase와 push_back을 통해 그래프의 상태를 원래대로 되돌리는 방법을 학습했습니다.

4, 최소값 갱신 로직

  • 문제의 조건에 맞는 최소값을 갱신하기 위해 min 함수와 절대값 계산을 활용했습니다.
  • 모든 경우를 탐색하고 최적의 결과를 도출하는 완전 탐색의 중요성을 다시 확인했습니다.

결론

이 문제를 통해 트리 구조의 그래프 문제를 해결하는 방법을 학습할 수 있었습니다. 특히, 인접 리스트를 사용해 그래프를 표현하는 방법BFS를 활용한 노드 탐색이 매우 유용한 도구임을 깨달았습니다. 앞으로도 유사한 그래프 문제에서 이 접근 방식을 활용할 수 있을 것입니다. 😊

반응형