아이디어
- 토네이도 표현
- 토네이도의 바람은 방향과 세기로 나눌 수 있다.
* 방향은 ←, ↓, →, ↑ 순서로 계속 회전한다.
- 세기는 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;
}
}
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;
}
}
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
리뷰
- 삼성은 토네이도를 좋아해
- 그래도 패턴을 찾으면 어렵지는 않다.