반응형
https://www.acmicpc.net/problem/20057
20057번: 마법사 상어와 토네이도
마법사 상어가 토네이도를 배웠고, 오늘은 토네이도를 크기가 N×N인 격자로 나누어진 모래밭에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c열을 의미하고, A[r][c]는 (r, c)에 있는 모래의 양을
www.acmicpc.net
풀이
위 문제는 맵 격자의 가운데 칸부터 토네이도가 이동을 시작한다.
한 번에 한 칸씩 이동하며 모래는 아래와 같은 비율로 흩날리게 된다.
static double[] per = {1,1,2,2,7,7,10,10,5,0};
static int[][] sdx = {
{-1,1,-2,2,-1,1,-1,1,0,0}, // 좌
{-1,-1,0,0,0,0,1,1,2,1}, // 하
{-1,1,-2,2,-1,1,-1,1,0,0}, // 우
{1,1,0,0,0,0,-1,-1,-2,-1}, // 상
};
static int[][] sdy = {
{1,1,0,0,0,0,-1,-1,-2,-1}, // 좌
{-1,1,-2,2,-1,1,-1,1,0,0}, // 하
{-1,-1,0,0,0,0,1,1,2,1}, // 우
{-1,1,-2,2,-1,1,-1,1,0,0}, // 상
};
4개의 방향으로 이동한다. 토네이도가 움직이는 방향에 따라서 흩날리는 모래의 위치 (x, y)가 달라진다. 미리 모래의 비율과 흩날리는 위치를 미리 넣어두고 시작하면 구현이 편해진다. 여기서 중요한 건 x 위치의 모래가 아닌 y 위치에 있는 모래가 흩날리며, a 에는 흩날리고 남은 모래가 남는다.
먼저 토네이도 이동에 대해서 알아보겠다.
토네이도 이동을 자세히 살펴보면 아래와 같은 규칙을 찾을 수 있다.
1칸, 1칸, 2칸, 2칸, ···
좌방향부터 시작해서 방향을 2번을 바꿀 때마다 1칸씩 증가한다.
public static void Move(int x, int y) {
int[] changeOfDir = {1, 1, 2, 2};
double ySand;
while (true) {
for (int d=0; d<4; d++) {
for (int i=0; i<changeOfDir[d]; i++) {
x += dx[d];
y += dy[d];
ySand = map[x][y];
if (ySand > 0) {
spread(x, y, d, ySand);
}
if (x == 0 && y == 0) {
return;
}
}
}
for (int k=0; k<4; k++) {
changeOfDir[k] += 2;
}
}
}
위 규칙으로 모든 칸을 이동하면서 모래의 비율만큼 해당 칸에 뿌려주면 된다.
<최종코드>
import java.io.*;
import java.util.*;
public class Main {
static int[] dx = {0, 1, 0, -1};
static int[] dy = {-1, 0, 1, 0};
static double[] per = {1,1,2,2,7,7,10,10,5,0};
static int[][] sdx = {
{-1,1,-2,2,-1,1,-1,1,0,0}, // 좌
{-1,-1,0,0,0,0,1,1,2,1}, // 하
{-1,1,-2,2,-1,1,-1,1,0,0}, // 우
{1,1,0,0,0,0,-1,-1,-2,-1}, // 상
};
static int[][] sdy = {
{1,1,0,0,0,0,-1,-1,-2,-1}, // 좌
{-1,1,-2,2,-1,1,-1,1,0,0}, // 하
{-1,-1,0,0,0,0,1,1,2,1}, // 우
{-1,1,-2,2,-1,1,-1,1,0,0}, // 상
};
static int[][] map;
static int N;
static int ans = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
N = Integer.parseInt(br.readLine());
map = new int[N][N];
for (int i=0; i<N; i++) {
st = new StringTokenizer(br.readLine());
for (int j=0; j<N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
Move(N/2, N/2);
System.out.println(ans);
}
public static void Move(int x, int y) {
int[] changeOfDir = {1, 1, 2, 2};
double ySand;
while (true) {
for (int d=0; d<4; d++) {
for (int i=0; i<changeOfDir[d]; i++) {
x += dx[d];
y += dy[d];
ySand = map[x][y];
if (ySand > 0) {
spread(x, y, d, ySand);
}
if (x == 0 && y == 0) {
return;
}
}
}
for (int k=0; k<4; k++) {
changeOfDir[k] += 2;
}
}
}
public static void spread(int x, int y, int d, double ySand) {
int nx, ny;
double spreadSands = 0; // 이동한 모래 양
// 남은 모래는 a 위치로 이동하기때문에 0
map[x][y] = 0;
for(int i=0; i<10; i++) {
nx = x + sdx[d][i];
ny = y + sdy[d][i];
int sand = (int) Math.floor(ySand / 100 * per[i]);
if (i == 9) {
double aSand = ySand - spreadSands; // 이동하고 남은 모래 양
if (!RangeCheck(nx,ny)) {
ans += aSand;
} else {
map[nx][ny] += aSand;
}
} else {
if (!RangeCheck(nx,ny)) {
ans += sand;
} else {
map[nx][ny] += sand;
}
spreadSands += sand;
}
}
}
public static boolean RangeCheck(int x, int y) {
return x >= 0 && x < N && y >= 0 && y < N ? true : false;
}
}
반응형
'알고리즘 > 구현 & 그리디 & 브루트포스' 카테고리의 다른 글
[백준]JAVA - 19236번: 청소년 상어 (1) | 2022.12.30 |
---|---|
[백준]JAVA - 20058번: 마법사 상어와 파이어스톰 (1) | 2022.12.22 |
[백준]JAVA - 21608번: 상어 초등학교 (0) | 2022.12.19 |
[백준]JAVA - 20055번: 컨베이어 벨트 위의 로봇 (0) | 2022.12.14 |
[백준]JAVA - 13460번: 구슬 탈출 2 (0) | 2022.12.12 |