[프로그래머스] 전력망을 둘로 나누기 (Javascript)

박먼지·2024년 6월 30일
0

코딩테스트

목록 보기
23/23
post-thumbnail

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

문제

n개의 송전탑이 전선을 통해 하나의 트리 형태로 연결되어 있습니다. 당신은 이 전선들 중 하나를 끊어서 현재의 전력망 네트워크를 2개로 분할하려고 합니다. 이때, 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고자 합니다.

송전탑의 개수 n, 그리고 전선 정보 wires가 매개변수로 주어집니다. 전선들 중 하나를 끊어서 송전탑 개수가 가능한 비슷하도록 두 전력망으로 나누었을 때, 두 전력망이 가지고 있는 송전탑 개수의 차이(절대값)를 return 하도록 solution 함수를 완성해주세요.

제한사항

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

입출력 예시

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번을 연결하는 전선을 끊어도 최선의 정답을 도출할 수 있습니다.

풀이

접근 방식

  1. 전선 정보를 저장할 데이터 구조를 정하고 저장한다.
    • 배열로 정한 이유는 구현하기 간단하고 순회하기 편하기 때문에
    • 연결된 모든 node를 표현해준다.
      ex) 1→3, 2→3, 3→1, 2, 4 ... = [[], [3], [3], [1,2,4], ...]
    const graph = Array.from({ length: n + 1 }, () => []);
     for (const [v1, v2] of wires) {
    	graph[v1].push(v2);
    	graph[v2].push(v1);
    }
  1. 이어져있는 전선의 수를 count하는 함수를 구현한다.

    • 시작 노드와 제외할 노드를 인자로 받는다.
    • 예를 들어 1→3인 경우 1번 송전탑과 3번 송전탑이 연결되어있다는 의미로 3→1과 동일한 경우이다. 따라서 중복 카운트를 방지하기 위해 visited 배열을 만들어서 방문 여부를 체크해준다.
    • 시작 노드와 연결되어 있는 노드를 순회하면서 제외할 노드가 아니면서 방문하지 않은 노드인 경우 방문처리를 하고, 큐에 넣는다.
    • 연결된 모든 노드를 순회한 후, 큐에 남아 있는 첫 번째 노드를 다시 순회하게 된다. 이는 해당 노드가 시작 노드와 연결되었다는 의미이므로 count를 증가시켜준다.
    • 해당 큐가 빌 때 까지 반복한다.(모든 노드 방문)
    const bfs = (start, except) => {
      let count = 0;
      const queue = [start];
      let visited = Array.from({ length: n + 1 }, () => false);
      visited[start] = true;
      while (queue.length !== 0) {
        const index = queue.shift();
        graph[index].forEach((v) => {
          if (v !== except && !visited[v]) {
            visited[v] = true;
            queue.push(v);
          }
        });
        count++;
      }
      return count;
    };
  2. 전선을 전부 순회하면서 나눠진 전력망이 가진 송전탑의 차이가 가장 적은 수를 return해준다.

    wires.forEach(([v1, v2]) => {
    	answer = Math.min(answer, Math.abs(bfs(v1, v2) - 	bfs(v2, v1)));
    });

전체 코드

function solution(n, wires) {
  const graph = Array.from({ length: n + 1 }, () => []);

  let answer = Number.MAX_SAFE_INTEGER;

  for (const [v1, v2] of wires) {
    graph[v1].push(v2);
    graph[v2].push(v1);
  }

  const bfs = (start, except) => {
    let count = 0;
    const queue = [start];
    let visited = Array.from({ length: n + 1 }, () => false);
    visited[start] = true;
    while (queue.length !== 0) {
      const index = queue.shift();
      graph[index].forEach((v) => {
        if (v !== except && !visited[v]) {
          visited[v] = true;
          queue.push(v);
        }
      });
      count++;
    }
    return count;
  };

  wires.forEach(([v1, v2]) => {
    answer = Math.min(answer, Math.abs(bfs(v1, v2) - bfs(v2, v1)));
  });

  return answer;
}
profile
개발괴발

0개의 댓글