구현 문제입니다.
구현 순서는 다음과 같습니다.
- 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동한다.
- 중복된 위치의 파이어볼을 합치고 분해한다.
- 남아있는 파이어볼의 질량을 더한다.
첫 번째는 이동했을 때 위치가 배열 밖에 있을 수 있다는 것을 유의해야 합니다. 문제 조건에 의해 1번 행, 열은 N번 행, 열과 연결되어있습니다. 때문에, 배열 범위를 벗어나면 반대편으로 이동시켜야 합니다.
두 번째는 삼차원 배열을 사용했습니다 자세한 것은 주석으로 달아놨으니 읽어보시기 바랍니다.
세 번째는 남아있는 파이어볼의 중량(m)만 더하시면 됩니다.
[구현 코드]
import java.io.*;
import java.util.*;
public class Main {
private static final int[] dx = {-1, -1, 0, 1, 1, 1, 0, -1}; // 상단부터 시계방향
private static final int[] dy = {0, 1, 1, 1, 0, -1, -1, -1};
private static int n, m, k;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer stz = new StringTokenizer(br.readLine(), " ");
int answer = 0;
n = Integer.parseInt(stz.nextToken());
m = Integer.parseInt(stz.nextToken());
k = Integer.parseInt(stz.nextToken());
List<Fireball> fireballs = new ArrayList<>();
for (int i = 0; i < m; i++) {
stz = new StringTokenizer(br.readLine(), " ");
int ri = Integer.parseInt(stz.nextToken()) - 1;
int ci = Integer.parseInt(stz.nextToken()) - 1;
int mi = Integer.parseInt(stz.nextToken());
int si = Integer.parseInt(stz.nextToken());
int di = Integer.parseInt(stz.nextToken());
fireballs.add(new Fireball(ri, ci, mi, si, di));
}
while (k-- > 0) {
int ballCount = fireballs.size();
int[][][] map = new int[n][n][ballCount]; // n*n개의 좌표에 최대 파이어볼의 개수 만큼 존재할 수 있음
// 1. 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동한다.
moveTheFireball(fireballs, ballCount, map);
// 2. 중복된 위치의 파이어볼을 합치고 분해한다.
fireballs = splitTheFireball(fireballs, ballCount, map);
}
// 3. 남아있는 파이어볼의 질량을 더한다.
for (Fireball fireball : fireballs) {
answer += fireball.m;
}
bw.write(String.valueOf(answer));
bw.flush();
bw.close();
br.close();
}
private static void moveTheFireball(List<Fireball> fireballs, int ballCount, int[][][] map) {
for (int i = 0; i < fireballs.size(); i++) {
Fireball fireball = fireballs.get(i);
int sx = dx[fireball.d] * fireball.s; // di 방향으로 si 만큼 이동
int sy = dy[fireball.d] * fireball.s;
int nx = adjustCoordinate(fireball.r, sx); // 좌표 조정
int ny = adjustCoordinate(fireball.c, sy);
for (int j = 0; j < ballCount; j++) {
if (map[nx][ny][j] == 0) { // nx, ny 좌표에 파이어볼을 위치시킴
map[nx][ny][j] = i + 1;
break;
}
}
// 이동된 좌표로 바꿈
fireball.r = nx;
fireball.c = ny;
}
}
private static int adjustCoordinate(int coordinate, int d) {
if (d < 0) d = (Math.abs(d) % n) * -1;
else d = d % n;
coordinate += d;
if (coordinate >= 0 && coordinate < n) {
return coordinate;
} else if (coordinate >= n) { // 좌표가 n보다 커질 때
return coordinate - n;
} else { // 좌표가 0보다 작을 때
return n + coordinate;
}
}
private static List<Fireball> splitTheFireball(List<Fireball> fireballs, int ballCount, int[][][] map) {
List<Fireball> move = new ArrayList<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (ballCount > 1 && map[i][j][1] > 0) { // i, j에 두 개 이상의 파이어볼이 있는 경우
int tm = 0;
int ts = 0;
int firstDirection = fireballs.get(map[i][j][0] - 1).d;
boolean isAllEvenOrOddDirection = true;
int cnt = 0;
for (int t = 0; t < ballCount; t++) {
if (map[i][j][t] == 0) break;
Fireball fireball = fireballs.get(map[i][j][t] - 1);
tm += fireball.m; // 합쳐진 파이어볼 질량의 합
ts += fireball.s; // 합쳐진 파이어볼 속력의 합
// 전부 홀수이거나 전부 짝수인지 확인
if (isAllEvenOrOddDirection) {
if (firstDirection % 2 != fireball.d % 2) {
isAllEvenOrOddDirection = false;
}
}
cnt++; // 합쳐진 파이어볼의 개수
}
for (int o = 0; o < 4; o++) {
int pm = tm / 5;
int ps = ts / cnt;
if (pm == 0) break;
if (isAllEvenOrOddDirection) {
move.add(new Fireball(i, j, pm, ps, o * 2));
} else {
move.add(new Fireball(i, j, pm, ps, (o * 2) + 1));
}
}
} else if (ballCount > 0 && map[i][j][0] > 0) { // 한 개의 파이어볼만 있는 경우
move.add(fireballs.get(map[i][j][0] - 1));
}
}
}
return move;
}
private static class Fireball {
int r, c, m, s, d;
public Fireball(int r, int c, int m, int s, int d) {
this.r = r;
this.c = c;
this.m = m;
this.s = s;
this.d = d;
}
}
}
'알고리즘' 카테고리의 다른 글
프로그래머스 - 당구 연습(Java) (0) | 2023.03.22 |
---|---|
프로그래머스 - 리코쳇 로봇(Java) (0) | 2023.03.21 |
백준 - 14890 경사로(Java) (0) | 2023.03.20 |
백준 - 20058 마법사 상어와 파이어스톰(Java) (0) | 2023.03.18 |
백준 - 17472 다리 만들기 2(Java) (0) | 2023.03.15 |