문제
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를 여러 번 해야하는 치즈랑 비슷한 문제인 것 같다.
아직 골드는 너무 어렵고 접근조차 못할 때가 많다ㅠㅠㅠ 골드라서 너무 어렵게만 생각하다보니 더 꼬이는 머리...
풀 수 있을 것 같은데 안풀리는게 진짜 킹받는다구....!
https://rookie-programmer.tistory.com/177
풀이
(0, 0)부터 방문되지 않은 땅 중, 인구 차이가 L명 이상, R명 이하인 땅들을 Q와 List에 수집한다. = 연합을 만든다.
Q에 값이 모두 비워질 때까지 = 연결된 땅들을 모두 살펴볼 때까지 반복하며, 최종적으로 연합이 생성되면 각 칸의 인구 수를 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)로 바꿔준다.
연합이 하나라도 생성되면 인구 이동이 일어날 수 있으니 isMove값을 true로 만들어주고,
전체 땅을 돌았음에도 연합이 생성되지 않았으면 isMove=false로 만들어주어 인구 이동이 일어나지 못하게 만든다.
if(!isMove) break; //국경 이동이 없을 때까지 반복
else cnt++; //국경 이동이 있었다면 일수 추가.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
class Country{
int x, y;
public Country(int x, int y) {
this.x = x;
this.y = y;
}
}
public class ex16234_인구이동 {
static final int dx[] = {-1, 0, 1, 0};
static final int dy[] = {0, 1, 0, -1};
static boolean visit[][];
static int map[][];
static int n, l, r, cnt;
static boolean isMove;
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());
map = new int[n][n];
for(int i=0; i<n; i++) {
st = new StringTokenizer(br.readLine());
for(int j=0; j<n; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
move();
System.out.println(cnt);
}
static void move() {
while(true) {
isMove = false;
visit = new boolean[n][n]; //새로 BFS 시작할때마다 방문 초기화
for(int i=0; i<n; i++) {
for(int j=0;j<n; j++) {
if(!visit[i][j]){
bfs(i,j); //방문하지 않은상태면 BFS 시작
}
}
}
if(!isMove) break; //국경 이동이 없을 때까지 반복
else cnt++; //국경 이동이 있었다면 일수 추가.
}
}
static void bfs(int x, int y){
Queue<Country> Q = new LinkedList<>();
List<Country> unionCountry = new ArrayList<>();
visit[x][y] = true;
Q.add(new Country(x, y));
unionCountry.add(new Country(x, y));
while(!Q.isEmpty()){
Country country = Q.poll();
x = country.x; // 수정된 부분: x, y를 현재 국가의 위치로 업데이트
y = country.y;
for (int i = 0; i < 4; i++) {
int nx = country.x + dx[i];
int ny = country.y + dy[i];
//다음 도시가 방문된 적 없고, NxN 범위 안에 있다면
if(nx>=0 && nx<n && ny>=0 && ny<n){
//현재 도시와 다음 도시와 연결될 수 있다면
if(!visit[nx][ny] && l <= Math.abs(map[x][y] - map[nx][ny]) && r >= Math.abs(map[x][y] - map[nx][ny])){
isMove = true; //국경 이동이 있으면 계속 반복되게 만듬.
visit[nx][ny]=true;
unionCountry.add(new Country(nx, ny));
Q.add(new Country(nx, ny));
}
}
}
}
//연합을 이루고 있는 각 칸의 인구수 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)로 세팅
int sum = 0;
for(Country country : unionCountry){
sum += map[country.x][country.y];
}
for(Country country : unionCountry){
map[country.x][country.y] = sum / unionCountry.size();
}
}
}
사실 답을 맞추기 전에는 while문에서 이런식으로 표현했지만 이 부분때문에 4번 테스트 케이스를 통과하지 못했다.
while(!Q.isEmpty()){
Country country = Q.poll();
for (int i = 0; i < 4; i++) {
int nx = country.x + dx[i];
int ny = country.y + dy[i];
while(!Q.isEmpty()){
Country country = Q.poll();
x = country.x; // 수정된 부분: x, y를 현재 국가의 위치로 업데이트
y = country.y;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
클래스 변수도 x, y, 매개변수도 x, y여서 생긴 문제였다.
bfs의 매개변수를 a, b로 바꿔주니 정상 동작했다.ㅎ_ㅎ
앞으로 함수 매개변수 이름은 조금 신경써서 지어야겠다.
이해하기 쉬운 코드가 있어 적어둔다.
https://easybrother0103.tistory.com/88
'Algorithm > 백준' 카테고리의 다른 글
[백준/JAVA] 🥈 1193번 분수찾기 (1) | 2024.01.04 |
---|---|
[백준/JAVA] 🥈 1138번 한 줄로 서기 (0) | 2023.12.30 |
[백준/JAVA] 🥈 1063번 킹 (1) | 2023.12.30 |
[백준/JAVA] 🥈 1051번 숫자 정사각형 (0) | 2023.12.29 |
[백준/JAVA] 🥈 1966번 프린터 큐 (1) | 2023.12.26 |