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

Bonwoong Ku·2023년 11월 1일
0

알고리즘 문제풀이

목록 보기
76/110

아이디어

  • 토네이도 표현
    • 토네이도의 바람은 방향과 세기로 나눌 수 있다.
      * 방향은 ←, ↓, →, ↑ 순서로 계속 회전한다.
      • 세기는 1, 1, 2, 2, 3, 3, ..., N-2, N-2, N-1, N-1, N-1과 같이 세기가 증가하며 2번씩 등장한 후, 추가로 N-1 세기의 바람이 분다.
    • 방향과 세기의 규칙성을 이용해 구하고, 세기 만큼 주어진 방향으로 바람 불기를 반복한다.
  • 바람 불기
    • 이동하는 칸(문제에서 y)를 중심으로 5x5의 임시 배열에 변경 값을 저장해둔다.
      • 바로 값을 변경하면 변경한 값을 다시 참조하게 되어 문제가 생긴다.
      • 변경값을 구하기 위해서는 방향에 맞게 회전시킨 비율 행렬을 참고해야 한다. 이 부분은 따로 함수로 만들어놓자.
    • 25칸에 대해 저장이 끝났다면 원래의 A[]에 반영한다.
      * 이때 범위를 벗어나게 된다면 답에 추가한다.
    • 반영이 끝나고 남은 임시배열의 중앙값 B[2][2]의 값은 α에 해당하는 칸에 추가한다.
      • 역시 이 칸이 범위를 벗어나는지 체크해야 한다.
    • 마지막으로 y 칸의 값을 0으로 만든다.

코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));
	static StringTokenizer tk = null;

	static int N, cy, cx, d, p, ans;
	static int[][] A;
	static int[][] B = new int[5][5];
	
	static int[][] pct = {
			{ 0,  0,  2,  0,  0},
			{ 0, 10,  7,  1,  0},
			{ 5,  0,  0,  0,  0},
			{ 0, 10,  7,  1,  0},
			{ 0,  0,  2,  0,  0},
	};
	
	static int[] dy = { 0,  1,  0, -1};
	static int[] dx = {-1,  0,  1,  0};
	
	public static void main(String[] args) throws Exception {
		N = Integer.parseInt(rd.readLine());
		
		A = new int[N][N];
		for (int y=0; y<N; y++) {
			tk = new StringTokenizer(rd.readLine());
			for (int x=0; x<N; x++) {
				A[y][x] = Integer.parseInt(tk.nextToken());
			}
		}
		
		cy = cx = N/2;
		for (int i=0; i < 2*N - 1; i++) {
			d = i % 4;
			p = Math.min((i / 2) + 1, N - 1);
			for (int j=0; j<p; j++) {
				int ny = cy + dy[d];
				int nx = cx + dx[d];
				blow(ny, nx, d);
				cy = ny;
				cx = nx;
			}
		}
		
		System.out.println(ans);
		
	}
	
	static void blow(int ey, int ex, int d) {
		int ny, nx;
		B[2][2] = A[ey][ex];
		for (int dy=-2; dy<=2; dy++) {
			for (int dx=-2; dx<=2; dx++) {
				ny = ey + dy;
				nx = ex + dx;
				int ds = (int) A[ey][ex] * rpct(d, dy, dx) / 100;
				B[dy+2][dx+2] += ds;
				B[2][2] -= ds;
			}
		}
		
		// commit
		for (int dy=-2; dy<=2; dy++) {
			for (int dx=-2; dx<=2; dx++) {
				if (dy == 0 && dx == 0) continue;
				ny = ey + dy;
				nx = ex + dx;
				if (ny < 0 || ny >= N || nx < 0 || nx >= N)
					ans += B[dy+2][dx+2];
				else
					A[ny][nx] += B[dy+2][dx+2];
				B[dy+2][dx+2] = 0;
			}
		}
		
		// alpha
		ny = ey + dy[d];
		nx = ex + dx[d];
		if (ny < 0 || ny >= N || nx < 0 || nx >= N)
			ans += B[2][2];
		else
			A[ny][nx] += B[2][2];
		
		A[ey][ex] = 0;
	}
	
	static int rpct(int d, int dy, int dx) {
		int y = dy + 2;
		int x = dx + 2;
		switch (d) {
		case 0:
			return pct[y][x];
		case 1:
			return pct[x][4-y];
		case 2:
			return pct[4-y][4-x];
		case 3:
			return pct[4-x][y];
		}
		return -999;
	}
	
} 

메모리 및 시간

  • 메모리: 150212 KB
  • 시간: 1000 ms

리뷰

  • 삼성은 토네이도를 좋아해
  • 그래도 패턴을 찾으면 어렵지는 않다.
profile
유사 개발자

0개의 댓글