문제 설명
주의사항
- 모듈러 연산
- 주어진 칸을 몇칸을 갈것인지에 대해 먼저 모듈러 연산을 하고 따로 전체에서 모듈러 연산을 진행해야 한다.
- 이동 조건 [이동 중복 이슈]왜냐하면 0,0에서 1,3으로 이동했을 때, 다시 1,3 배열을 순회하는 부분에서 또 이동이 발생하기 때문이다.
- 이동할 때 배열의 복사를 진행해야한다.
- 2-4 번 조건
- 질량이 0인 파이어볼은 소멸되어 없어진다. [소멸되어 없어짐은 곧 해당 배열에 있는 기존 파이어볼도 다 없애야 함.]
풀이
static int dy[] = {-1, -1, 0, 1, 1, 1, 0, -1};
static int dx[] = {0, 1, 1, 1, 0, -1, -1, -1};
private static int n;
static class FireBall {
int y, x, amount, speed, dir;
public FireBall(int y, int x, int amount, int speed, int dir) {
this.y = y;
this.x = x;
this.amount = amount;
this.speed = speed;
this.dir = dir;
}
public int getAmount() {
return amount;
}
public int getSpeed() {
return speed;
}
public int getDir() {
return dir;
}
public FireBall getNext() {
int ny = (this.y + dy[dir] * (speed % n) + n) % n;
int nx = (this.x + dx[dir] * (speed % n) + n) % n;
return new FireBall(ny, nx, amount, speed, dir);
}
}
static LinkedList<FireBall> map[][];
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(reader.readLine());
// 격자 크기
n = Integer.parseInt(st.nextToken());
map = new LinkedList[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
map[i][j] = new LinkedList<>();
}
}
int m = Integer.parseInt(st.nextToken()); // 파이어볼 개수
int k = Integer.parseInt(st.nextToken()); // 명령문의 개수
for (int i = 0; i < m; i++) {
st = new StringTokenizer(reader.readLine());
int y = Integer.parseInt(st.nextToken()) - 1;
int x = Integer.parseInt(st.nextToken()) - 1;
int amount = Integer.parseInt(st.nextToken());
int speed = Integer.parseInt(st.nextToken());
int dir = Integer.parseInt(st.nextToken());
FireBall fireBall = new FireBall(y, x, amount, speed, dir);
map[y][x].add(fireBall);
}
while (k-- > 0) {
// 1. 이동
map = move();
// 2. 2개이상의 파이어볼 찾고 합치기
integrate();
}
int answer = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
LinkedList<FireBall> fireBalls = map[i][j];
if (fireBalls.isEmpty())
continue;
answer += fireBalls
.stream()
.map(FireBall::getAmount)
.reduce(Integer::sum)
.orElseGet(() -> 0);
}
}
System.out.println(answer);
}
// 2-4 질량이 0인 파이어볼은 소멸되어 없어진다. 조건 잘 봐야함 그리고 [소멸되어 없어짐은 곧 해당 배열에 있는 기존 파이어볼도 다 없애야 함.]
private static void integrate() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
LinkedList<FireBall> fireBalls = map[i][j];
if (fireBalls.size() < 2)
continue;
Integer totalAmount = fireBalls.stream()
.map(FireBall::getAmount)
.reduce(Integer::sum)
.orElseGet(() -> 0);
if (totalAmount / 5 == 0) {
map[i][j].clear();
continue;
}
Integer totalSpeed = fireBalls.stream()
.map(FireBall::getSpeed)
.reduce(Integer::sum)
.orElseGet(() -> 0);
List<Integer> dirs = fireBalls.stream().map(FireBall::getDir).collect(Collectors.toList());
boolean isEven = dirs.stream().allMatch(dir -> dir % 2 == 0);
boolean isOdd = dirs.stream().allMatch(dir -> dir % 2 == 1);
LinkedList<FireBall> newLists = new LinkedList<>();
if (isEven || isOdd) {
for (int dir = 0; dir < 8; dir += 2) {
newLists.add(
new FireBall(
i,
j,
totalAmount / 5,
totalSpeed / fireBalls.size(),
dir)
);
}
} else {
for (int dir = 1; dir < 8; dir += 2) {
newLists.add(
new FireBall(
i,
j,
totalAmount / 5,
totalSpeed / fireBalls.size(),
dir)
);
}
}
map[i][j] = newLists;
}
}
}
// 이미 이동을 했음에도 불구하고 배열을 순회할때 중복으로 움직이는 이슈가 있어 복사해야함.
private static LinkedList<FireBall>[][] move() {
LinkedList<FireBall> newMap[][] = new LinkedList[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
newMap[i][j] = new LinkedList<>();
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
LinkedList<FireBall> fireBalls = map[i][j];
while (!fireBalls.isEmpty()) {
FireBall cur = fireBalls.poll();
FireBall next = cur.getNext();
newMap[next.y][next.x].add(next);
}
}
}
return newMap;
}
'Algorithm > 백준' 카테고리의 다른 글
백준 - 나무 재태크 (0) | 2023.03.18 |
---|---|
백준 - 나무 위의 빗물 (0) | 2023.03.16 |
백준 - 단절점과 단절선 (0) | 2023.03.14 |
백준 - 미세먼지 안녕! (0) | 2023.03.13 |
마법사 상어와 비바라기 (1) | 2023.03.12 |
댓글