| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- 스프링부트 배포
- 프로그래머스 2개 이하로 다른 비트
- 둘만의 암호 자바
- 백트래킹
- Ubuntu서버
- 프로그래머스
- 분할정복 알고리즘
- Comparable
- systemd
- LocalDate
- 오블완
- 리눅스
- BFS
- java
- 분할정복
- DFS
- spring security
- hackerrank
- 티스토리챌린지
- 알고리즘
- 프로그래머스 둘만의 암호
- SQL Mapper
- 자바의 정석
- 서버초기설정
- EC2배포
- 자바의정석
- 둘만의 암호
- spring security 설정
- AWS배포
- 혼공얄코
- Today
- Total
쉽게 쉽게
[프로그래머스] 전력망을 둘로 나누기 (Java) — BFS 본문
- 트리의 성질 — 노드 n개, 간선 n-1개면 트리. 간선 하나를 끊으면 정확히 두 개의 컴포넌트로 갈라진다.
- 완전탐색으로 충분 — n ≤ 100이라 간선 99개를 전부 끊어봐도 여유롭게 통과한다. 그리디하게 고민할 필요가 없다.
- 한쪽만 세면 끝 — 한쪽 크기가
count면 반대쪽은n - count. 차이는Math.abs(count - (n - count)). - 트리라서 가능한 단순화 — 간선을 끊는 대신 반대편 노드 하나를 차단하는 것으로 같은 효과를 낼 수 있다.
1 문제 소개
n개의 송전탑이 전선을 통해 하나의 트리 형태로 연결되어 있다. 전선 중 하나를 끊어 전력망을 2개로 분할하려고 한다. 이때 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고, 그 개수 차이(절댓값)를 반환하는 문제다.
- wires 배열로 양방향 인접 리스트를 만든다.
- 간선을 하나씩 "끊었다고 가정"하며 전부 시도한다 (완전탐색).
- 끊은 간선의 한쪽 끝에서 BFS를 돌려 그쪽 컴포넌트의 크기
count를 센다. 이때 반대편 노드를 차단해 간선을 끊은 효과를 낸다. Math.abs(count - (n - count))로 두 그룹의 차이를 구하고 최솟값을 갱신한다.
2 접근 아이디어
노드 n개 + 간선 n-1개 = 트리
문제를 읽고 처음 눈에 들어온 건 "송전탑 n개, 전선 n-1개"라는 조건이었다. 이건 그래프 이론에서 아주 특별한 형태, 바로 트리라는 뜻이다. 사이클이 없는 연결 그래프이기 때문에, 트리에서 간선 하나를 끊으면 정확히 두 개의 덩어리로 갈라진다는 게 보장된다.
완전탐색으로 충분한 이유
n이 최대 100이므로 간선은 최대 99개다.
"간선을 하나씩 끊어보고 → 매번 결과를 확인"하는 완전탐색을 해도 간선 99개 × 탐색 O(n) 수준이라 시간은 전혀 문제가 되지 않는다.
어떤 간선을 끊어야 유리할지 그리디하게 고민할 필요 없이, 전부 끊어보면 된다.
한쪽 크기만 세면 반대쪽은 공짜
전체가 n개인데 한쪽이 count개라면, 나머지는 자동으로 n - count개다.
그래서 BFS는 한 번만 돌리면 되고, 두 그룹의 차이는 아래 한 줄로 정리된다.
count - (n - count)는 count가 작은 쪽 덩어리인지 큰 쪽 덩어리인지에 따라 음수가 될 수 있다. 문제가 원하는 건 부호 없는 "차이"이므로 Math.abs로 절댓값을 씌운다. 이게 없으면 음수 diff가 Math.min에서 부당하게 이겨버려 답이 망가진다. 3 BFS 설계 — 간선 대신 노드를 차단하기
트리라서 가능한 단순화
"간선 (a, b)를 끊는다"를 구현하는 가장 정직한 방법은 BFS 중에 a→b, b→a 양방향 이동을 모두 검사해서 막는 것이다.
그런데 트리에서는 더 단순한 방법이 있다. a에서 출발하는 BFS가 b 쪽 덩어리로 건너가는 통로는 그 간선 하나뿐이므로, "b 노드 자체를 밟지 않는다"는 조건 하나로 간선을 끊은 것과 완전히 같은 효과가 난다.
BFS의 핵심: 확인 → 도장 → 예약
BFS에서 큐에 넣는다는 건 "나중에 방문할 것을 예약한다"는 뜻이다. 그래서 visited의 실제 의미는 "방문 완료"가 아니라 "큐에 들어간 적 있음(예약됨)"이고, 도장은 큐에 넣는 시점에 찍어야 한다. 순서는 항상 이 세 동작이 한 세트다.
- 확인 —
!visited[next]아직 예약 안 된 노드인지 검사한다. - 도장 —
visited[next] = true즉시 예약됨 표시를 남긴다. - 예약 —
queue.add(next)그 다음에 큐에 넣는다.
visited[next] = true로 표시는 했지만 넣기 전에 이미 방문한 노드인지 확인을 안 했다. 양방향 그래프에서는 노드 1과 2가 서로를 계속 다시 큐에 넣는 핑퐁이 벌어져서, count가 틀리는 정도가 아니라 while문이 영원히 끝나지 않는다. 표시만 하고 확인을 안 하면 표시가 아무 역할을 못 한다는 걸 몸으로 배웠다.4 전체 코드 (Java)
import java.util.*;
class Solution {
// 여러 메서드에서 함께 쓰기 위해 필드로 선언
private List<List<Integer>> graph;
public int solution(int n, int[][] wires) {
int answer = n; // 어떤 diff도 n 이상이 될 수 없으므로 n으로 초기화
// 1. 인접 리스트 구성 (인덱스 = 노드 번호, 0번은 버림 칸)
graph = new ArrayList<>();
for (int i = 0; i <= n; i++) {
graph.add(new ArrayList<>());
}
for (int[] wire : wires) {
graph.get(wire[0]).add(wire[1]);
graph.get(wire[1]).add(wire[0]); // 무방향이므로 양방향 등록
}
// 2. 간선을 하나씩 끊어보며 완전탐색
for (int[] wire : wires) {
// wire[0]에서 시작, wire[1] 노드를 차단
int count = bfs(wire[0], wire[1], n);
// 3. 두 그룹의 크기 차이로 최솟값 갱신
int diff = Math.abs(count - (n - count));
answer = Math.min(answer, diff);
}
return answer;
}
// start에서 출발하되 blocked 노드로는 이동하지 않는 BFS
private int bfs(int start, int blocked, int n) {
boolean[] visited = new boolean[n + 1];
Queue<Integer> queue = new LinkedList<>();
// 4. 시작 노드를 예약(큐 삽입)하고 도장 찍기
queue.add(start);
visited[start] = true;
int count = 0;
while (!queue.isEmpty()) {
int cur = queue.poll();
count++;
for (int next : graph.get(cur)) {
// 5. 차단 노드이거나 이미 예약된 노드면 패스
if (next == blocked || visited[next]) continue;
visited[next] = true;
queue.add(next);
}
}
// 6. start 쪽 컴포넌트의 크기 반환
return count;
}
}
5 시간복잡도
BFS 한 번은 노드와 간선을 모두 훑으므로 O(V+E) = O(n)이고, 전체는 O(n²)이다.
n ≤ 100이므로 최악에도 1만 번 수준의 연산이라 아주 여유롭다.
| 단계 | 연산 | 복잡도 | 비고 |
|---|---|---|---|
| 그래프 구성 | 간선 n-1개를 양방향 등록 | O(n) | 1회 |
| BFS 1회 | 컴포넌트 크기 세기 | O(n) | 여유 |
| 전체 | 간선 수 × BFS | O(n²) | n ≤ 100이라 충분 |
| 잘못된 내용이 있다면 지적부탁드립니다. 방문해주셔서 감사합니다. |

'알고리즘 > BFS (너비 우선 탐색)' 카테고리의 다른 글
| [프로그래머스] 무인도 여행 — BFS (1) | 2026.07.16 |
|---|---|
| [프로그래머스] 미로 탈출 (Java) - BFS (0) | 2026.07.08 |
| [프로그래머스] 리코쳇 로봇(Java) - BFS (1) | 2026.01.27 |
| [프로그래머스] 타겟 넘버(DFS/BFS) -Java (0) | 2025.12.03 |
| [프로그래머스] 게임 맵 최단거리(BFS) -Java (0) | 2025.12.03 |
