발자취

[프로그래머스 Lv.2 / C++] Day76. 전력망을 둘로 나누기 본문

코딩테스트/Daily Coding (C, C++)

[프로그래머스 Lv.2 / C++] Day76. 전력망을 둘로 나누기

해린 2024. 8. 18. 20:54

2024. 08. 18 - 코딩테스트 스터디 Day76

 
 

01. 문제 설명

n개의 송전탑이 전선을 통해 하나의 트리 형태로 연결되어 있습니다. 당신은 이 전선들 중 하나를 끊어서 현재의 전력망 네트워크를 2개로 분할하려고 합니다. 이때, 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고자 합니다.
송전탑의 개수 n, 그리고 전선 정보 wires가 매개변수로 주어집니다. 전선들 중 하나를 끊어서 송전탑 개수가 가능한 비슷하도록 두 전력망으로 나누었을 때, 두 전력망이 가지고 있는 송전탑 개수의 차이(절댓값)를 return 하도록 solution 함수를 완성해 주세요.

 
 

02. 제한사항

  • n은 2 이상 100 이하인 자연수입니다.
  • wires는 길이가 n-1인 정수형 2차원 배열입니다.
    • wires의 각 원소는 [v1, v2] 2개의 자연수로 이루어져 있으며, 이는 전력망의 v1번 송전탑과 v2번 송전탑이 전선으로 연결되어 있다는 것을 의미합니다.
    • 1 ≤ v1 < v2 ≤ n입니다.
    • 전력망 네트워크가 하나의 트리 형태가 아닌 경우는 입력으로 주어지지 않습니다.

 
 

03. 입출력 예

nwiresresult
9[[1,3],[2,3],[3,4],[4,5],[4,6],[4,7],[7,8],[7,9]]3
4[[1,2],[2,3],[3,4]]0
7[[1,2],[2,7],[3,7],[3,4],[4,5],[6,7]]1

 
입출력 예 설명
입출력 예 #1

  • 다음 그림은 주어진 입력을 해결하는 방법 중 하나를 나타낸 것입니다.
  • 4번과 7번을 연결하는 전선을 끊으면 두 전력망은 각 6개와 3개의 송전탑을 가지며, 이보다 더 비슷한 개수로 전력망을 나눌 수 없습니다.
  • 또 다른 방법으로는 3번과 4번을 연결하는 전선을 끊어도 최선의 정답을 도출할 수 있습니다.

입출력 예 #2

  • 다음 그림은 주어진 입력을 해결하는 방법을 나타낸 것입니다.
  • 2번과 3번을 연결하는 전선을 끊으면 두 전력망이 모두 2개의 송전탑을 가지게 되며, 이 방법이 최선입니다.

입출력 예 #3

  • 다음 그림은 주어진 입력을 해결하는 방법을 나타낸 것입니다.
  • 3번과 7번을 연결하는 전선을 끊으면 두 전력망이 각각 4개와 3개의 송전탑을 가지게 되며, 이 방법이 최선입니다.

 
 

4. 풀이 및 답

#include <string>
#include <vector>
#include <cmath>
#include <queue>
#define MAX 101

using namespace std;

int count;
vector<int> connect[101];

void bfs(int v1, int v2) {
    queue<int> q;
    vector<int> visit(MAX);
    
    q.push(v1);
    visit[v1] = 1;
    visit[v2] = 1;
    
    while (!q.empty()) {
        int node = q.front();
        q.pop();
        
        for (int i = 0; i < connect[node].size(); i++) {
            int node2 = connect[node][i];
            
            if (visit[node2]) continue;
            
            count++;
            q.push(node2);
            visit[node2] = 1;
        }
    }
}

int solution(int n, vector<vector<int>> wires) {
    int answer = MAX;
    
    for (auto x : wires) {
        connect[x[0]].push_back(x[1]);
        connect[x[1]].push_back(x[0]);
    }
    
    for (auto x : wires) {
        count = 1;
        int v1 = x[0];
        int v2 = x[1];
        
        bfs(v1, v2);
        answer = min(answer, abs(2 * count - n));
    }
    
    return answer;
}

BFS 탐색 시 서브 트리의 노드 개수를 저장하는 count 변수와 각 송전탑에 연결된 다른 송전탑의 번호를 저장하는 connect 벡터를 선언했다.
 
main
우선 wires 배열 속 정보를 통해 각 송전탑의 연결 관계를 connect에 저장한다.
예를 들어, wires 벡터에 [1,3]과 같은 요소가 존재한다면 connect[1]에 3을, connect[3]에 1을 push 한다.
그 뒤, 모든 전선을 한 번씩 끊어보면서 해당 전선으로 이루어진 두 송전탑을 각각 v1, v2로 두고 bfs 함수를 사용하여 각 두 전력망의 송전탑 개수의 차이를 계산한다. 이렇게 계산된 두 전력망의 송전탑 개수의 차이 중 최소를 찾아 갱신해 나간다.
 
bfs
q에 시작 노드를 넣고, 두 노드의 방문 여부를 표시하는 visit 배열의 값을 1로 바꾼다.
(v1은 시작 노드이므로 제외, v2는 방문하면 안 되기 때문에 제외하는 것이다.)
그 뒤, v1과 연결된 노드 중 아직 방문하지 않은 노드가 있다면 count를 증가시키고, q에 push 한 뒤 방문 처리를 하면서 송전탑 개수를 찾는다.
 

정답!


오늘 문제는 너무 어려워서 다른 분들의 풀이를 보고 이해하는 방식으로 풀어봤다
DFS, BFS는 너무 어려운 것 같다 허허
 
참고한 게시글

[프로그래머스] 전력망을 둘로 나누기 C++ (Lv.2)

https://school.programmers.co.kr/learn/courses/30/lessons/86971 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는

cherishvert.tistory.com