인구이동 구현방법에 대해 설명을 하겠습니다.
이 방법은 개인적인 방법이며 최적의 솔루션이 아닐 수 있습니다.
우선, 문제를 먼저 보면
문제설명
1. 국경선을 공유하는 나라 즉, 상하좌우에 있는 나라와 인구 수의 차이가 L명 이상 R명 이하로 난다면 두 나라는 국경선을 연다.
2. 국경선을 열 수 있는 나라가 모두 열리면 인구이동을 시작한다.
3. 인구이동이 시작되면 연합을 이룬 나라의 인구 수는 (연합의 인구 수) / (연합을 이루고 있는 칸의 개수) , 소수점 이하는 버림.
4. 이후 연합을 해체하고 모든 국경선을 닫는다.(연합을 이뤘던 각 나라의 인구 수는 (연합의 인구 수) / (연합을 이루고 있는 칸의 개수)로 유지)
5. 더이상 인구이동을 할 수 없을 때까지의 일 수를 구해야한다.
구현방법
가장 깊게 생각했던 부분 (개인적)
★ BFS 함수를 시작하는 첫 좌표의 국경선 여는 나라의 LIST에 포함하는 방법
-> 해결방법 : check 변수 사용
★ 하루에 두 곳 이상에서 한 번에 인구이동이 일어났을 때 해결방법
-> 해결방법1 : bfs함수 종료 직후 국경선이 열렸는지 확인 후 인구이동한 후 다음 방문 안한 나라 bfs함수 실행
-> 해결방법2 : temp 변수를 이용한 while문 종료조건
자세한 구현 방법은 코드 주석을 통해 설명드리도록 하겠습니다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
import java.util.*;
import java.io.*;
class Node{
int x,y;
Node(int x, int y){
this.x = x;
this.y = y;
}
int getX() {
return x;
}
int getY() {
return y;
}
}
public class Main{
static int n;
static int l, r;
static int[][] graph; //인구수가 나와있는 배열
static boolean[][] visited; //방문한 곳 체크하는 배열
static int[] dx = {0,0,-1,1};
static int[] dy = {-1,1,0,0};
static ArrayList<Node> move = new ArrayList<>(); //인구이동이 일어나는 좌표 저장
static int result; //인구이동이 일어나는 곳 인구 수 합
static void bfs(int x, int y) {
Queue<Node> q = new LinkedList<>();
q.offer(new Node(x, y));
visited[x][y] = true;
boolean check = false;
/*
* check는 맨 처음 좌표를 제크하고
* 비교 후 인구이동이 일어나는 곳이면
* 리스트에 포함하기 위해 사용하는 변수
*/
while(!q.isEmpty()) {
int k = q.size();
for(int i=0;i<k;i++) {
Node node = q.poll();
x = node.getX();
y = node.getY();
for(int j=0;j<4;j++) {
int nx = x+dx[j];
int ny = y+dy[j];
if(nx>=n||ny>=n||nx<0||ny<0)
continue;
if(visited[nx][ny])
continue;
/*
* graph배열 내 좌표이고 방문하지 않았으며,
* x,y좌표와 nx,ny 좌표 차이의 절대값이ㅣ이상,
* r이하이면 국경선이 열린다.
*/
if(Math.abs(graph[nx][ny]-graph[x][y])>=l&&Math.abs(graph[nx][ny]-graph[x][y])<=r) {
q.offer(new Node(nx,ny));
visited[nx][ny] = true;
/*
* check는 위에서 말했듯이 함수의 맨 처음 좌표가
* 인구이동을 하는 나라에 포함이 된다면
* check를 true하여 다음 좌표들은 조건이 성립하지 않도록한다.
*/
if(!check) {
result += graph[x][y];
move.add(new Node(x, y));
check = true;
}
/*
* 인구이동을 하는 나라에 포함이 된다면
* result에 인구 값을 더하고
* 국경선 여는 나라 list에 포함 시킨다.
*/
result += graph[nx][ny];
move.add(new Node(nx, ny));
}
}
}
}
}
public static void main(String args[]) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer stok = new StringTokenizer(br.readLine());
n = Integer.parseInt(stok.nextToken());
l = Integer.parseInt(stok.nextToken());
r = Integer.parseInt(stok.nextToken());
graph = new int[n][n];
visited = new boolean[n][n];
for(int i=0;i<n;i++) {
stok = new StringTokenizer(br.readLine());
for(int j=0;j<n;j++) {
graph[i][j] = Integer.parseInt(stok.nextToken());
}
}
int cnt = 0;
result = 0;
move = new ArrayList<>();
while(true) {
visited = new boolean[n][n];//하루가 지날때마다 방문 배열은 초기화한다.
int temp = 0; //while문 종료조건
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(!visited[i][j]) {
bfs(i,j);
if(result>0) {//bfs함수를 통해 국경선을 여는 나라가 있으면
int k = move.size();
for(Node node:move) {//국경선을 여는 나라들 평균값을 넣어준다(소수점 이하 버림)
graph[node.getX()][node.getY()] = result/k;
}
//초기화
result = 0;
move = new ArrayList<>();
temp++;
}
}
}
}
if(temp==0) //그래프 전체를 탐색해도 국경선을 여는 나라가 없으면 while문 종료
break;
cnt++; //하루씩 증가
}
bw.write(String.valueOf(cnt));
bw.flush();
}
}
|
cs |
구현을 마무리하고 보니 고민했던 부분은 아무것도 아닌것처럼 보였다,, 저것들 때문에 1시간이나 고민했는데,,,
아직 경험이 많이 부족해서 그런거라고 생각하고 열심히 코테준비를 해야겠다 !!!
'Study > CodingTest' 카테고리의 다른 글
[BOJ 1449] 수리공 항승 - JAVA (0) | 2022.07.30 |
---|---|
[BOJ 15904] UCPC는 무엇의 약자일까? - JAVA (0) | 2022.07.26 |
[BOJ 11047] 동전 0 - JAVA (0) | 2022.07.25 |
[BOJ 2573] 빙산 - JAVA (0) | 2022.02.05 |
[BOJ 16236] 아기상어 - JAVA (0) | 2022.02.01 |