백준 20057 - 마법사 상어와 토네이도
Updated:
Java
20057 번 - 마법사 상어와 토네이도
문제
접근 방법
전체적인 구현 순서는 다음과 같다.
- 회전하는 토네이도 이동방향 구현
 - 방향에 따른 퍼지는 모래의 비율 2차원 List로 설정
 - 모래를 퍼뜨린다
 
토네이도의 회전 방향은 [좌 -> 하] / [우 -> 상] 이 각각 반복 될 때 마다, 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);
    }
}
