문제
N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다.
오늘부터 인구 이동이 시작되는 날이다.
인구 이동은 하루 동안 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다.
- 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 오늘 하루 동안 연다.
- 위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
- 국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 오늘 하루 동안은 연합이라고 한다.
- 연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)가 된다. 편의상 소수점은 버린다.
- 연합을 해체하고, 모든 국경선을 닫는다.
각 나라의 인구수가 주어졌을 때, 인구 이동이 며칠 동안 발생하는지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N, L, R이 주어진다. (1 ≤ N ≤ 50, 1 ≤ L ≤ R ≤ 100)
둘째 줄부터 N개의 줄에 각 나라의 인구수가 주어진다. r행 c열에 주어지는 정수는 A[r][c]의 값이다. (0 ≤ A[r][c] ≤ 100)
인구 이동이 발생하는 일수가 2,000번 보다 작거나 같은 입력만 주어진다.
출력
인구 이동이 며칠 동안 발생하는지 첫째 줄에 출력한다.
풀이
선택 알고리즘
BFS - 국경선을 이을 수 있는지 여부는 2차원배열의 상하좌우로 탐색하는 방식에 유리한 BFS를 선정함
시간 복잡도
전체 후보를 모두 방문해야 하고, NxN 배열을 방문하므로 N제곱 X N제곱 (BFS)
N의 네제곱이므로, 50 X 50 X 50 X 50 = 6,250,000으로 계산
구현
- 모든 땅을 방문하여, 국경선을 열 수 있는 경우, 국경선을 공유 가능한 모든 땅의 좌표를 arrayList에 담아서 보관하고, 탐색이 끝났다면 큐에 보관한 어레이리스트를 저장 → 인구 이동이 일어나는 경우가 하루에 여러 땅에서 일어날 수 있기 때문에 각각 관리해줘야 한다.
- 큐가 비어있지 않다면 어레이리스트를 꺼내서 국경선을 공유하는 모든 땅의 값을 업데이트 해줌
- 만약 그 어디도 방문하지 못했다면 (국경선을 공유할 수 있는 땅이 없다면), 종료한다.
코드
package com.company.baekjoon;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class BaekJoon16234 {
static int N;
static int L;
static int R;
static int[][] arr;
static boolean[][] union;
static Queue<int[]> queue;
static Queue<ArrayList<int[]>> a = new LinkedList<>();
static ArrayList<int[]> arrayList = new ArrayList<>();
static int[] dx = new int[] { -1, 1, 0, 0};
static int[] dy = new int[] { 0, 0, -1, 1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
L = Integer.parseInt(st.nextToken());
R = Integer.parseInt(st.nextToken());
int answer = 0;
arr = new int[N][N];
union = new boolean[N][N];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
arr[i][j] = Integer.parseInt(st.nextToken());
}
}
queue = new LinkedList<>();
while (true) {
for (boolean booleans[]: union) {
Arrays.fill(booleans, false);
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (!union[i][j]) {
queue.add(new int[]{i,j});
bfs();
if (arrayList.size() > 0) {
a.add((ArrayList<int[]>) arrayList.clone());
arrayList.clear();
}
}
}
}
while (!a.isEmpty()) {
ArrayList<int[]> list = a.poll();
int size = list.size();
int sum = 0;
if (size == 0) { // 인구이동 후보가 없음
break;
}
for (int k = 0; k < size; k++) {
int[] n = list.get(k);
sum += arr[n[0]][n[1]];
}
int value = sum / size;
for (int k = 0; k < size; k++) {
int[] n = list.get(k);
arr[n[0]][n[1]] = value;
}
}
arrayList.clear();
// 만약 더이상 진행할 수 없을 경우 (아무 지역도 후보가 될 수 없는 경우)
boolean isContinue = false;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (union[i][j])
isContinue = true;
}
}
if (!isContinue)
break;
// 모든 나라 검사 다 했으면 1 증가함.
answer++;
}
System.out.println(answer);
}
public static void bfs() {
while (!queue.isEmpty()) {
int[] nation = queue.poll();
for (int i = 0; i < dx.length; i++) {
int currentX = nation[0] + dx[i];
int currentY = nation[1] + dy[i];
if (currentX < 0 || currentX >= N || currentY < 0 || currentY >= N) continue;
if (union[currentX][currentY]) continue; // 이미 방문한경우
if (Math.abs(arr[nation[0]][nation[1]] - arr[currentX][currentY]) >= L &&
Math.abs(arr[nation[0]][nation[1]] - arr[currentX][currentY]) <= R) { // 국경이 열림
if (!union[nation[0]][nation[1]]) {
union[nation[0]][nation[1]] = true;
arrayList.add(new int[]{nation[0], nation[1]});
}
union[currentX][currentY] = true;
queue.add(new int[]{currentX, currentY});
arrayList.add(new int[]{currentX, currentY});
}
}
}
}
}
'알고리즘' 카테고리의 다른 글
[백준] 2568번 전깃줄 - 2 자바 풀이 (0) | 2023.08.23 |
---|---|
[백준] 3109번 빵집 자바 풀이 (0) | 2023.08.17 |
[백준] 2615번 오목 자바 풀이 (0) | 2023.08.01 |
[백준] 15649번 N과 M (1) 자바 풀이 (0) | 2023.08.01 |
[백준] 1244번 스위치 켜고 끄기 풀이 (0) | 2023.08.01 |