Loading [MathJax]/jax/output/CommonHTML/jax.js

알고리즘/구현 & 그리디 & 브루트포스

[백준]JAVA - 20058번: 마법사 상어와 파이어스톰

K.두부 2022. 12. 22. 21:39
반응형

https://www.acmicpc.net/problem/20058

 

20058번: 마법사 상어와 파이어스톰

마법사 상어는 파이어볼과 토네이도를 조합해 파이어스톰을 시전할 수 있다. 오늘은 파이어스톰을 크기가 2N × 2N인 격자로 나누어진 얼음판에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c

www.acmicpc.net

풀이

요즘 마법사 상어 시리즈를 풀어보고있는데 파이어스톰 마법을 배웠다고 한다...

위 문제는 아래와 같은 과정을 거친다.

 

  1. 파이어스톰 단계를 L이라고 가정했을 때, (0, 0)을 시작으로 2Lx2L 크기의 부분 격자로 나눈다.
  2. 모든 부분 격자를 시계 방향으로 90도 회전시킨다.
  3. 특정 칸에서 인접해있는 칸 중 얼음이 존재하는 칸이 3개 미만이라면 특정 칸의 얼음의 양이 1 줄어든다.
  4. 위 과정을 Q번 반복한다.

1. 파이어스톰 단계를 L이라고 가정했을 때, (0, 0)을 시작으로 2Lx2L 크기의 부분 격자로 나눈다.

public static void fireStorm(int step) {
tmp = new int[mapSize][mapSize];
for (int i=0; i<mapSize; i+=step) {
for (int j=0; j<mapSize; j+=step) {
rotate(i, j, step); // 회전
}
}
map = tmp;
}

 

2. 모든 부분 격자를 시계 방향으로 90도 회전시킨다.

public static void rotate(int x, int y, int level) {
for (int i=0; i<level; i++) {
for (int j=0; j<level; j++) {
tmp[x+i][y+j] = map[x+level-j-1][y+i];
}
}
}

부분 격자가 만들어지면 위 그림처럼 이동한다. 

회전하는 식을 찾는데 엄청나게 오랜 시간을 소비했다..

 

3. 특정 칸에서 인접해있는 칸 중 얼음이 존재하는 칸이 3개 미만이라면 특정 칸의 얼음의 양이 1 줄어든다.

public static void meltIce() {
tmp = new int[mapSize][mapSize];
for (int i=0; i<mapSize; i++) {
for (int j=0; j<mapSize; j++) {
if (map[i][j] == 0) continue;
int cnt = 0;
for (int d=0; d<4; d++) {
int nx = i + dx[d];
int ny = j + dy[d];
if (nx < 0 || ny < 0 || nx > mapSize-1 || ny > mapSize-1) continue;
if (map[nx][ny] > 0) {
cnt++;
}
}
if (cnt < 3) {
tmp[i][j] = map[i][j] - 1;
} else {
tmp[i][j] = map[i][j];
}
}
}
map = tmp;
}

bfs를 이용해서 인접하고 있는 얼음칸을 찾는다. 3개 미만이면 얼음양을 1 줄이고, 그렇지않다면 그대로 두면 된다. bfs를 돌리는 과정에서 값이 변경되면 얼음칸이었던 곳이 아니게 될 수 있기 때문에 임시 배열을 만들어서 bfs가 끝나면 다시 map 배열에 복사한다.

 

<최종코드>

import java.io.*;
import java.util.*;
public class Main {
static int N, mapSize, max_ice = 0;
static int[][] map, tmp;
static int[] dx = {0, 1, 0, -1};
static int[] dy = {1, 0, -1, 0};
static boolean[][] visited;
public static class Ice {
int x, y;
public Ice (int x, int y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
int Q = Integer.parseInt(st.nextToken());
mapSize = (int) Math.pow(2, N);
map = new int[mapSize][mapSize];
for (int i=0; i<mapSize; i++) {
st = new StringTokenizer(br.readLine());
for (int j=0; j<mapSize; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
int[] step = new int[Q];
st = new StringTokenizer(br.readLine());
for (int i=0; i<Q; i++) {
step[i] = Integer.parseInt(st.nextToken());
}
for (int i=0; i<Q; i++) {
fireStorm((int) Math.pow(2, step[i]));
meltIce();
}
int ans = 0;
visited = new boolean[mapSize][mapSize];
for (int i=0; i<mapSize; i++) {
for (int j=0; j<mapSize; j++) {
ans+= map[i][j];
if (!visited[i][j] && map[i][j] > 0) {
findIce(i, j);
}
}
}
System.out.println(ans);
System.out.println(max_ice);
}
public static void fireStorm(int step) {
tmp = new int[mapSize][mapSize];
for (int i=0; i<mapSize; i+=step) {
for (int j=0; j<mapSize; j+=step) {
rotate(i, j, step);
}
}
map = tmp;
}
public static void rotate(int x, int y, int level) {
for (int i=0; i<level; i++) {
for (int j=0; j<level; j++) {
tmp[x+i][y+j] = map[x+level-j-1][y+i];
}
}
}
public static void meltIce() {
tmp = new int[mapSize][mapSize];
for (int i=0; i<mapSize; i++) {
for (int j=0; j<mapSize; j++) {
if (map[i][j] == 0) continue;
int cnt = 0;
for (int d=0; d<4; d++) {
int nx = i + dx[d];
int ny = j + dy[d];
if (nx < 0 || ny < 0 || nx > mapSize-1 || ny > mapSize-1) continue;
if (map[nx][ny] > 0) {
cnt++;
}
}
if (cnt < 3) {
tmp[i][j] = map[i][j] - 1;
} else {
tmp[i][j] = map[i][j];
}
}
}
map = tmp;
}
public static void findIce(int x, int y) {
int ice = 1;
Queue<Ice> q = new LinkedList<>();
q.add(new Ice(x, y));
visited[x][y] = true;
while (!q.isEmpty()) {
Ice now = q.poll();
for (int i=0; i<4; i++) {
int nx = now.x + dx[i];
int ny = now.y + dy[i];
if (nx < 0 || ny < 0 || nx > mapSize-1 || ny > mapSize-1 || visited[nx][ny] || map[nx][ny] == 0) continue;
q.add(new Ice(nx, ny));
visited[nx][ny] = true;
ice++;
}
}
max_ice = Math.max(ice, max_ice);
}
}

 

반응형