공기청정기
는 항상 1번 열
에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼지가 있고, (r, c)에 있는 미세먼지의 양은 Ar,c이다.
1초 동안 아래 적힌 일이 순서대로 일어난다.
Ar,c/5
이고 소수점은 버린다. 즉, ⌊Ar,c/5⌋이다.Ar,c - ⌊Ar,c/5⌋×(확산된 방향의 개수)
이다.위쪽
공기청정기의 바람은 반시계방향
으로 순환하고, 아래쪽
공기청정기의 바람은 시계방향
으로 순환한다.미세먼지가 없는 바람
이고, 공기청정기로 들어간 미세먼지는 모두 정화된다.import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Baek_17144 {
static int[] dx = {-1,0,1,0};
static int[] dy = {0,1,0,-1};
static int[][] box;
static int head, foot;
static int r,c,t;
static int[][] dust() {
int[][] copymap = new int[r][c];
copymap[head][0] = -1;
copymap[foot][0] = -1;
for(int i=0; i<r; i++) {
for(int j=0; j<c; j++) {
if(box[i][j] > 0) {
copymap[i][j] += box[i][j];
for(int k=0; k<4; k++) {
int nx = i + dx[k];
int ny = j + dy[k];
if(nx>=0 && nx<r && ny>=0 && ny<c && box[nx][ny] != -1) {
copymap[nx][ny] += (box[i][j] / 5);
copymap[i][j] -= (box[i][j] / 5);
}
}
}
}
} // end for
return copymap;
}
static void airup() {
for(int i= head-1; i>0; i--) {
box[i][0] = box[i-1][0];
}
for(int i=0; i<c-1; i++){
box[0][i] = box[0][i+1];
}
for(int i=0; i<head; i++) {
box[i][c-1] = box[i+1][c-1];
}
for(int i = c-1; i>1; i--) {
box[head][i] = box[head][i-1];
}
box[head][1] = 0;
}
static void airdown() {
for (int x = foot + 1; x < r - 1; x++) {
box[x][0] = box[x + 1][0];
}
for (int y = 0; y < c - 1; y++) {
box[r - 1][y] = box[r - 1][y + 1];
}
for (int x = r - 1; x > foot; x--) {
box[x][c - 1] = box[x - 1][c - 1];
}
for (int y = c - 1; y > 1; y--) {
box[foot][y] = box[foot][y - 1];
}
box[foot][1] = 0;
}
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(bf.readLine());
r = Integer.parseInt(st.nextToken());
c = Integer.parseInt(st.nextToken());
t = Integer.parseInt(st.nextToken());
box = new int[r][c]; // 7 x 8
for(int i=0; i<r; i++) {
st = new StringTokenizer(bf.readLine());
for(int j=0; j<c; j++) {
box[i][j] = Integer.parseInt(st.nextToken());
}
}
for(int i=0; i<r; i++) {
if(box[i][0] == -1) {
head = i;
foot = i + 1;
break;
}
}
for(int i=0; i<t; i++) {
box = dust();
airup();
airdown();
}
int sum = 2;
for(int i=0; i<r; i++) {
for(int j=0; j<c; j++) {
sum += box[i][j];
}
}
System.out.println(sum);
}
}
dust()
라는 함수를 만들고 원본배열(box) 에서 문제의 조건에 따라 변경되는 값
들을 업데이트 해줄 배열
이 필요했고 copymap
이라는 배열에 그 값들을 저장했다. for(int i=0; i<r; i++) {
for(int j=0; j<c; j++) {
if(box[i][j] > 0) {
copymap[i][j] += box[i][j];
for(int k=0; k<4; k++) {
int nx = i + dx[k];
int ny = j + dy[k];
if(nx>=0 && nx<r && ny>=0 && ny<c && box[nx][ny] != -1) {
copymap[nx][ny] += (box[i][j] / 5);
copymap[i][j] -= (box[i][j] / 5);
}
}
}
}
} // end for
이 부분이 미세먼지가 퍼져나가는 과정에서 가장 중요하다고 느꼈고 머리로 알지만 실제 구현하는데 있어 많은 시간을 허비한 부분이다.
0 30 7
0 10 0
0 0 0
이라는 원본 map
이라는 배열이 있다고 해보자.
먼저 배열의 값이 0보다 크다
면 미세먼지가 존재
한다는 말과 같다.
따라서 내가 값을 업데이트 하려는 새로운배열(copymap)
에 해당 값(예를 들어 위 예시 배열에서 30 이라고 하자) 을 저장한다.
0 30 0
0 0 0
0 0 0
그러면 copymap 의 배열 상태는 위와 같게 된다. 여기서 이제 해당 값 기준으로 상하좌우를 살펴 인덱스범위조건과 -1이 아니라면 밑의 과정
copymap[nx][ny] += (box[i][j] / 5);
copymap[i][j] -= (box[i][j] / 5);
을 통해서 copymap[nx][ny] 에 box[i][j] / 5 를 더해준다. 즉 예시로 보면 30/5 = 6 을 더하는것과 같다. ( 아직 오른쪽만 했을 때)
0 30 6
0 0 0
0 0 0
그렇게 된다면 다음과 같이 copymap 이 업데이트 될 것이고, 이제 copymap[i][j] -= (box[i][j] / 5); , 즉 업데이트가 되어야 할 copymap 배열의 [i][j] 의 값, 즉 예시로는 30에서 box[i][j] / 5 값을 뺴준다. 굳이 방향의 개수를 계산해서 "값 x 방향" 을 안해줘도 되는 이유는 갈 수 있는 방향만 간다음 값이 바뀌기 때문에 굳이 "값 x 방향" 으로 처리해주지 않았다.
처음에 copymap을 깊은 복사로 box 을 복사하여 사용하려 했었다. 하지만 그렇게 된다면 값이 업데이트되면서 중복되는 값들이 생기고, 결과가 달라지게 된다. 따라서 copymap 을 사용할 때 초기화만 해준 후, 조건에 만족할 때마다 box 배열에서 값을 가져왔다.
static void airup() {
for(int i= head-1; i>0; i--) {
box[i][0] = box[i-1][0];
}
for(int i=0; i<c-1; i++){
box[0][i] = box[0][i+1];
}
for(int i=0; i<head; i++) {
box[i][c-1] = box[i+1][c-1];
}
for(int i = c-1; i>1; i--) {
box[head][i] = box[head][i-1];
}
box[head][1] = 0;
}
이 부분은 문제에서 언급한 위쪽 공기청정기
의 작동을 표현한 코드이다.
여기서 주목해야 할 부분은 다음과 같다.
위쪽
공기청정기의 바람은 반시계
방향으로 분다.먼저 1번을 살펴보자.
만약 먼저 오른쪽으로 부는 바람만을 생각했을 때, 바람이 반시계 방향으로 분다해서 단순히 왼쪽에 있는 배열의 값을 바람이 부는 방향인 오른쪽으로 업데이트해주면 될까?
그렇지 않다. 그렇게 되면 왼쪽-> 오른쪽 으로 값이 변경되면서 순차적으로원하지 않는 업데이트된 값
들이오른쪽에 저장
되게 된다.
따라서 반대방향인시계방향
으로, 즉역
으로 값들을 땡겨오면서 업데이트하게되면 원하는 값을 얻을 수 있다.
airdown() 의 방향만 반대고 원리는 같으므로 생략한다.
2번은 간단하다.
공기청정기에서 부는 바람은 미세먼지가 없다( = 공기청정기의 바로 오른쪽의 값은 0이다. ) 와 같은 말이다.
box[head][1] = 0;
box[foot][1] = 0;
으로 설정한 뒤 함수를 종료한다.
마지막으로 문제에서 요구한 미세먼지의 총합을 계산한다.
모든 배열의 원소들을 더하는데 그렇게되면 원하지않는 공기청정기의 값(-1) 이 2개 생기게된다. 따라서 sum의 초깃값을 2
로 설정해둔 후 계산해주면 간단히 원하는 sum 이 나온다.
< 입력 >
7 8 1
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
< 출력 >
188