Today's special moments become memories of tomorrow.

BOJ/삼성 SW 역량테스트

[백준 20057번] 마법사 상어와 토네이도 (java)

lotus lee 2021. 4. 23. 20:42

 

20057번: 마법사 상어와 토네이도

마법사 상어가 토네이도를 배웠고, 오늘은 토네이도를 크기가 N×N인 격자로 나누어진 모래밭에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c열을 의미하고, A[r][c]는 (r, c)에 있는 모래의 양을

www.acmicpc.net

토네이도의 방향 순서가 서쪽 -> 남쪽 -> 동쪽 -> 북쪽 순서대로 반복된다.

 

direct 3차원 배열을 만들어서,

- 첫 번째 인덱스는 방향(0: 서쪽, 1:남쪽, 2:동쪽, 3:북쪽)을 의미하고,

- 두 번째 인덱스는 0일 경우 r 좌표(행 좌표), 1일 경우 c 좌표(열 좌표)를 나타내었다.

- 세 번째 인덱스는 현재 위치를 기준으로 1%비율에 해당하는 위치, 2%에 해당하는 위치,

   5%에 해당하는 위치, 7%에 해당하는 위치, 10%에 해당하는 위치, 알파에 해당하는 위치를 나타냈다.

 

int[][][] direct = new int[4][2][10];

{ { 1, -1, 2, -2, 0, 1, -1, 1, -1, 0 }, { 1, 1, 0, 0, -2, 0, 0, -1, -1, -1 } },    <- 서쪽 방향일 때 각 비율의 좌표
{ { -1, -1, 0, 0, 2, 0, 0, 1, 1, 1 }, { -1, 1, -2, 2, 0, -1, 1, -1, 1, 0 } },      <- 남쪽 방향일 때 각 비율의 좌표
{ { 1, -1, 2, -2, 0, 1, -1, 1, -1, 0 }, { -1, -1, 0, 0, 2, 0, 0, 1, 1, 1 } },      <- 동쪽 방향일 때 각 비율의 좌표
{ { 1, 1, 0, 0, -2, 0, 0, -1, -1, -1 }, { -1, 1, -2, 2, 0, -1, 1, -1, 1, 0 } }    <- 북쪽 방향일 때 각 비율의 좌표

 };

 

예를 들어, 위의 그림은 현재 토네이도가 서쪽방향으로 부는 경우에 해당한다.

 

만약 모래의 기존 위치가 (r, c)일 때 7%인 위치를 찾으려면?

: 먼저 현재 방향은 서쪽이므로 첫번째 인덱스는 0이 된다. (0: 서쪽, 1:남쪽, 2:동쪽, 3:북쪽) -> direct[0][?][?]

  그리고 세번째 인덱스에서 7%에 해당하는 인덱스는 아래의 빨간색 부분이다. (인덱스 5와 6)

  -> direct[0][?][5] & direct[0][?][6]

 

{ { 1, -1, 2, -2, 0, 1, -1, 1, -1, 0 }, { 1, 1, 0, 0, -2, 0, 0, -1, -1, -1 } },    <- 서쪽 방향일 때 각 비율의 좌표
{ { -1, -1, 0, 0, 2, 0, 0, 1, 1, 1 }, { -1, 1, -2, 2, 0, -1, 1, -1, 1, 0 } },      <- 남쪽 방향일 때 각 비율의 좌표
{ { 1, -1, 2, -2, 0, 1, -1, 1, -1, 0 }, { -1, -1, 0, 0, 2, 0, 0, 1, 1, 1 } },      <- 동쪽 방향일 때 각 비율의 좌표
{ { 1, 1, 0, 0, -2, 0, 0, -1, -1, -1 }, { -1, 1, -2, 2, 0, -1, 1, -1, 1, 0 } }    <- 북쪽 방향일 때 각 비율의 좌표

 };

 

두번째 인덱스는 0일 때 r 좌표, 1일 때 c 좌표이다.

따라서 7% 비율에 해당하는 위치는

(r + direct[0][0][5], c + direct[0][1][5]) 와 (r + direct[0][0][6], c + direct[0][1][6])이다.

 

 

moveSand() 메서드는 y에 있는 모래가 0보다 클 때, 그 모래를 비율에 맞춰 흩어보내는 메서드이다.

위의 direct 배열을 이용하여 모래를 적절히 분배하고, 만약 NxN 범위를 벗어나면 경계 밖으로 나간 것이므로 total에 나간 모래양만큼 더해준다.

	public static void moveSand(int r, int c, int d) {

		int rest = A[r][c]; // 기존의 모래양

		for (int i = 0; i < 9; i++) {  // 9가지 경우에 맞추어 모래 흩뿌리기
			int nr = r + direct[d][0][i]; 
			int nc = c + direct[d][1][i];

			int amount = (int) Math.floor(A[r][c] * (double) (percent[i] / 100.0));
			rest -= amount;

            // 경계 안에 있으면 기존의 모래양에 amount 더해주기
			if ((1 <= nr && nr <= N) && (1 <= nc && nc <= N)) {
				A[nr][nc] += amount;
			}

			else // 경계를 벗어나면 total에 모래양 더하기
				total += amount;
		}

		int nr = r + direct[d][0][9]; // (r,c)를 기준으로 알파의 r 좌표
		int nc = c + direct[d][1][9]; // (r,c)를 기준으로 알파의 c 좌표

        // 경계 안에 있으면 기존의 모래양에 amount 더해주기
		if ((1 <= nr && nr <= N) && (1 <= nc && nc <= N)) {
			A[nr][nc] += rest;
			A[r][c] = 0;
		}

		else  // 경계를 벗어나면 total에 모래양 더하기
			total += rest;
	}

 

 

전체 코드 :