백준 20057 - 마법사 상어와 토네이도

Updated:

Java

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

문제

접근 방법

전체적인 구현 순서는 다음과 같다.

  1. 회전하는 토네이도 이동방향 구현
  2. 방향에 따른 퍼지는 모래의 비율 2차원 List로 설정
  3. 모래를 퍼뜨린다

토네이도의 회전 방향은 [좌 -> 하] / [우 -> 상] 이 각각 반복 될 때 마다, 2칸 씩 더 이동하도록 하였다.

MAP 크기는 의도적으로 행/렬 4줄씩 늘려서 Map 외부로 모래가 퍼지는 값을 저장하도록 하였다.
따라서, MAP 내부는 (2 <= y < n + 2) , (2 <= x < n + 2) 이다.

토네이도에 의하여 모래가 퍼지는 위치(비율)은,
우선 좌측으로 토네이도가 이동할 때 모래가 퍼지는 위치와 비율을 2차원 배열로 저장하였고,
위 행렬을 90도씩 회전시키면서 좌,우,상 방향의 퍼지는 위치와 비율을 계산하였다.

코드

import java.util.*;
import java.io.*;

public class Main {
	static int n, result;
	static int[][] map;

	// 좌, 하, 우, 상
	static int[] dy = {0,1,0,-1};
	static int[] dx = {-1,0,1,0};

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	StringTokenizer stk;
    	n = stoi(br.readLine());

    	map = new int[n + 4][n + 4];

    	for(int i = 2; i < n + 2; i++) {
    		stk = new StringTokenizer(br.readLine());
    		for(int j = 2; j < n + 2; j++) {
    			map[i][j] = stoi(stk.nextToken());
    		}
    	}

    	int dir = 0, dist = 1;
    	int moveCnt = 0;
    	int y = (n / 2) + 2;
    	int x = (n / 2) + 2;
    	makeWind();
    	// 토네이도 이동
    	end : while(true) {

    		for(int rp = 0; rp < 2; rp++) {
    			for(int i = 0; i < dist; i++) {
    				// 마지막 점 도달
    				if(moveCnt == (n * n) - 1)
    					break end;

        			y = y + dy[dir];
            		x = x + dx[dir];
					// 현재 토네이도 위치에서 모래를 퍼뜨린다.
            		Spread(y,x,dir);
            		moveCnt++;
        		}

        		dir = (dir + 1) % 4;
    		}
    		dist++;
    	}
		// 전체 모래의 개수를 더 한다.
    	for(int i = 0; i < n + 4; i++) {
    		for(int j = 0; j < n + 4; j++) {
    			result += map[i][j];
    		}
    	}
		// map 범위 내부에 남아있는 모래의 개수를 뺀다.
    	for(int i = 2; i < n + 2; i++) {
    		for(int j = 2; j < n + 2; j++) {
    			result -= map[i][j];
    		}
    	}

    	System.out.println(result);

    	br.close();
	}

	// 모래를 퍼뜨린다.
	static List<int[][]> wind;
	static void Spread(int y, int x, int dir) {

		int ny,nx, calS;
		int sum = 0;
		for(int i = 0; i < 5; i++) {
			for(int j = 0; j < 5; j++) {
				// 해당 방향으로 토네이도가 모래를 밀쳤을 때 밀린다면,
				if(wind.get(dir)[i][j] != 0) {
					ny = y + (i - 2);
					nx = x + (j - 2);

					calS = (map[y][x] * wind.get(dir)[i][j]) / 100;
					map[ny][nx] += calS;
					sum += calS;
				}
			}
		}

		ny = y + dy[dir];
		nx = x + dx[dir];

		map[ny][nx] += (map[y][x] - sum);
		map[y][x] = 0;
	}
	// 모래 퍼뜨리는 위치
	static void makeWind() {
		wind = new ArrayList<>();
		// 좌
		int[][] temp = new int[5][5];
		temp[0][2] = 2;
		temp[1][1] = 10;
		temp[1][2] = 7;
		temp[1][3] = 1;
		temp[2][0] = 5;
		temp[3][1] = 10;
		temp[3][2] = 7;
		temp[3][3] = 1;
		temp[4][2] = 2;

		wind.add(temp);

		// 하
		int[][] rotate = new int[5][5];
		for(int i = 0; i < 5; i++) {
			for(int j = 0; j < 5; j++) {
				rotate[i][j] = temp[j][5-1-i];
			}
		}
		wind.add(rotate);

		// 우
		rotate = new int[5][5];
		for(int i = 0; i < 5; i++) {
			for(int j = 0; j < 5; j++) {
				rotate[i][j] = temp[5 - 1 - i][5 - 1 - j];
			}
		}
		wind.add(rotate);

		// 상
		rotate = new int[5][5];
		for(int i = 0; i < 5; i++) {
			for(int j = 0; j < 5; j++) {
				rotate[i][j] = temp[5 - 1 - j][i];
			}
		}
		wind.add(rotate);
	}

	static int stoi(String str) {
    	return Integer.parseInt(str);
    }
}

총평

후기

개선할 점