[BOJ 20057] 마법사 상어와 토네이도
업데이트:
문제
- BOJ 20057
- 문제의 저작권은 Baekjoon Online Judge에 있습니다.
접근방식
- 달팽이 숫자로
map
을 탐색한다.- 그림을 그려보면 이동 칸수가
dist
이고 1 1 2 2 3 3… 씩 하나씩 증가하면서 2번 반복한 후 방향이 바뀌는 것을 알 수 있다. 예외적으로 마지막dist
일 때는 3번 반복되므로 한번 더 해준다. 이를 이용해 다음 좌표를 구하고 이동시킨다.
- 그림을 그려보면 이동 칸수가
-
move(int dist)
에서dist
만큼 반복해서 현재 방향으로 이동한다. - 모래를 흩날리기 위해
spread(int nx, int ny)
를 호출한다.- 현재 총 모래양을
total
에 저장하고, 각 비율 별 뿌려야할 모래양, 나머지양을 변수에 저장한다. - 현재 방향에 따라 넣어줘야할 비율의 좌표를 구하고,
check(int x, int y)
에서 범위 체크 후 이를 만족하면 해당 좌표map[nx][ny]
에amount
를 누적해준다. - 격자 밖인 경우에 답이 되므로
Ans
에 누적해준다. - 좌표는 현재 방향이 좌,우일때 같고 상,하일때 같은 점을 이용해 구한다.
- 현재 총 모래양을
- 1,1까지 오면 탐색종료 후
Ans
를 출력한다.
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static int N;
static int[][] map; // 모래양 저장
static int[][] dArr = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } }; // 좌하우상
static int nowX, nowY, nowD; // 현재 좌표, 방향
static int Ans; // 격자밖으로 나간 모래양
public static void main(String[] args) throws IOException {
N = Integer.parseInt(br.readLine());
map = new int[N + 1][N + 1];
for (int i = 1; i <= N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 1; j <= N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
} // End input
// 시작점 구하기
nowX = (N + 1) / 2;
nowY = (N + 1) / 2;
nowD = 0;
// 달팽이숫자로 이동 시작
int dist = 1;
boolean flag = true;
while (flag) {
for (int cnt = 0; cnt < 2; cnt++) { // 2번 반복
move(dist);
if(nowX == 1 && nowY == N) {
move(dist);
flag = false;
break;
}
}
dist++;
}
System.out.println(Ans);
}
private static void move(int dist) {
for (int k = 0; k < dist; k++) { // 이동칸 수
int nx = nowX + dArr[nowD][0];
int ny = nowY + dArr[nowD][1];
spread(nx, ny); // 모래 흩날리기
nowX = nx;
nowY = ny;
}
nowD = (nowD + 1) % 4;
}
private static void check(int nx, int ny, int amt) {
if (nx >= 1 && nx <= N && ny >= 1 && ny <= N) map[nx][ny] += amt;
else Ans += amt; // 격자밖
}
private static void spread(int nx, int ny) {
int total = map[nx][ny]; // 총 모래 양
map[nx][ny] = 0;
int amt1 = (int) (total * 0.01); // 2번 넣음
int amt2 = (int) (total * 0.02); // 2번
int amt5 = (int) (total * 0.05); // 1번
int amt7 = (int) (total * 0.07); // 2번
int amt10 = (int) (total * 0.1); // 2번
int a = total - 2 * (amt1 + amt2 + amt7 + amt10) - amt5;// 나머지 양(알파에 넣을 양) = total에서 amt1~10뺀거
int ax = nx + dArr[nowD][0];
int ay = ny + dArr[nowD][1];
if (nowD == 0 || nowD == 2) { // 좌우
// 1%
check(nowX - 1, nowY, amt1);
check(nowX + 1, nowY, amt1);
// 7%
check(nx - 1, ny, amt7);
check(nx + 1, ny, amt7);
// 2%
check(nx - 2, ny, amt2);
check(nx + 2, ny, amt2);
// 10%
check(ax - 1, ay, amt10);
check(ax + 1, ay, amt10);
// 5%
check(ax + dArr[nowD][0], ay + dArr[nowD][1], amt5);
} else if (nowD == 1 || nowD == 3) { // 상하
// 1%
check(nowX, nowY - 1, amt1);
check(nowX, nowY + 1, amt1);
// 7%
check(nx, ny - 1, amt7);
check(nx, ny + 1, amt7);
// 2%
check(nx, ny - 2, amt2);
check(nx, ny + 2, amt2);
// 10%
check(ax, ay - 1, amt10);
check(ax, ay + 1, amt10);
// 5%
check(ax + dArr[nowD][0], ay + dArr[nowD][1], amt5);
}
check(ax, ay, a);
}
}