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

[필자 사고]
각 노드들을 이분법 으로 나누는 방법 뭐 없을까?
비트마스킹을 이용하여 이분화를 진행할 수 있다.
이분화를 진행한 뒤에 BFS를 이용하여 실제로 인접한지 확인한다. 인접하지 않으면 false 인접하면 성공
그리고 A와 N가 모두 인접했으면 answer 즉 population 차이를 갱신한다. 최소값으로
아래는 자세한 코드 해설이다.
[코드 해설]
1. bool BFS(vector<int>& area, vector<bool>& selected)
이 함수는 특정 선거구(area)가 연결되어 있는지 검사하는 역할을 한다.
- queue<int> q를 사용하여 BFS(너비 우선 탐색)를 수행한다.
- visited 벡터는 각 구역이 탐색되었는지 여부를 기록한다.
- 시작점으로 선거구의 첫 번째 구역 area[0]을 큐에 넣고 방문 표시를 한다.
- 큐가 빌 때까지 반복하면서 다음을 수행한다.
- 현재 구역을 꺼내어(now) 방문한 구역 수(cnt)를 하나 증가시킨다.
- 현재 구역과 인접한 구역(next)을 순회한다.
- 아직 방문하지 않았고, 같은 선거구에 속한 구역(selected[next] == selected[now])이라면
방문 처리 후 큐에 추가한다.
- BFS가 종료되면, 실제로 방문한 구역 수(cnt)가 선거구의 전체 구역 수(area.size())와 같으면
선거구가 모두 연결되어 있다고 판단하여 true를 반환한다.
그렇지 않으면 false를 반환한다.
2. void Game_Start()
이 함수는 가능한 모든 선거구 분할 조합을 탐색하고,
두 선거구 간 인구 차이의 최솟값을 계산한다.
- for (int mask = 1; mask < (1 << N) - 1; mask++)
이 반복문은 비트마스크를 이용해 모든 가능한 구역 분할 조합을 순회한다.
예를 들어, mask의 각 비트가 1이면 해당 구역은 A 선거구에, 0이면 B 선거구에 속한다.
단, 모든 구역이 한쪽에만 몰린 경우(0 또는 (1<<N)-1)는 제외한다. - 반복 내부에서는 두 벡터 A와 B를 만들어 구역을 나눈다.
selected 배열은 각 구역이 어떤 선거구에 속하는지를 기록한다.
(true면 A, false면 B) - 두 선거구가 모두 비어 있지 않은지 확인하고,
두 선거구 각각이 연결되어 있는지 BFS()로 검사한다.
하나라도 연결되어 있지 않으면 해당 조합은 건너뛴다. - 두 선거구가 모두 연결되어 있으면,
각 선거구의 인구 합(popA, popB)을 구하고
그 차이의 절댓값을 계산해 answer에 최솟값으로 갱신한다.
3. int main(void)
프로그램의 진입점으로, 입력을 처리하고 전체 과정을 실행한다.
- 첫 줄에서 구역의 개수 N을 입력받는다.
- 각 구역의 인구를 population 벡터에 저장한다.
- 이후 각 구역의 인접한 구역 정보를 입력받아 adjacnt 벡터에 저장한다.
이 벡터는 인접 리스트로, adjacnt[i]에는 i번 구역과 직접 연결된 구역들의 번호가 담긴다. - 모든 입력이 끝나면 Game_Start() 함수를 호출해 가능한 모든 분할을 탐색하고
인구 차이의 최솟값을 계산한다. - answer가 초기값(1e9)에서 변하지 않았다면,
즉 두 선거구로 나눌 수 없는 경우이므로 -1을 출력한다.
그렇지 않으면 최소 인구 차이를 출력한다.
[소스 코드]
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
int N;
vector<int> population;
vector<vector<int>> adjacnt;
int answer = 1e9;
bool BFS(vector<int>& area, vector<bool>& selected) {
queue<int> q;
vector<bool> visited(N + 1, false);
q.push(area[0]);
visited[area[0]] = true;
int cnt = 0;
while (!q.empty()) {
int now = q.front();
q.pop();
cnt++;
for (int next : adjacnt[now]) {
if (!visited[next] &&
selected[next] == selected[now]) {
visited[next] = true;
q.push(next);
}
}
}
return cnt == area.size();
}
void Game_Start() {
for (int mask = 1; mask < (1 << N) - 1; mask++) {
vector<int> A, B;
vector<bool> selected(N + 1, false);
for (int i = 0; i < N; i++) {
if (mask & (1 << i)) {
A.push_back(i + 1);
selected[i + 1] = true;
}
else {
B.push_back(i + 1);
}
}
if (A.empty() || B.empty())continue;
if (!BFS(A, selected))continue;
if (!BFS(B, selected))continue;
int popA = 0, popB = 0;
for (int i : A)popA += population[i];
for (int i : B) popB += population[i];
answer = min(answer, abs(popA - popB));
}
}
int main(void) {
cin >> N;
population.assign(N + 1, 0);
adjacnt.resize(N + 1);
for (int i = 1; i <= N; i++) {
cin >> population[i];
}
for (int i = 1; i <= N; i++) {
int count;
cin >> count;
for (int k = 0; k < count; k++) {
int num;
cin >> num;
adjacnt[i].push_back(num);
}
}
Game_Start();
if (answer == 1e9) cout << -1;
else cout << answer;
}'백준 > 그래프' 카테고리의 다른 글
| 백준 14226 c++ "이모티콘" -PlusUltraCode- (0) | 2025.03.09 |
|---|---|
| 백준 11559 c++ "Puyo Puyo" -PlusUltraCode- (0) | 2025.03.08 |
| 백준 1240 c++ "노드사이의 거리" -PlusUltraCode- (0) | 2025.03.06 |
| 백준 18405 c++ "경쟁적 전염" -PlusUltraCode- (0) | 2025.03.05 |
| 백준 16928 c++ "뱀과 사다리 게임" -PlusUltraCode- (0) | 2025.03.04 |