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



풀이
요즘 마법사 상어 시리즈를 풀어보고있는데 파이어스톰 마법을 배웠다고 한다...
위 문제는 아래와 같은 과정을 거친다.
- 파이어스톰 단계를 L이라고 가정했을 때, (0, 0)을 시작으로 2Lx2L 크기의 부분 격자로 나눈다.
- 모든 부분 격자를 시계 방향으로 90도 회전시킨다.
- 특정 칸에서 인접해있는 칸 중 얼음이 존재하는 칸이 3개 미만이라면 특정 칸의 얼음의 양이 1 줄어든다.
- 위 과정을 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); } }
반응형
'알고리즘 > 구현 & 그리디 & 브루트포스' 카테고리의 다른 글
[백준]JAVA - 1027번: 고층 건물 (1) | 2022.12.31 |
---|---|
[백준]JAVA - 19236번: 청소년 상어 (1) | 2022.12.30 |
[백준]JAVA - 20057번: 마법사 상어와 토네이도 (0) | 2022.12.20 |
[백준]JAVA - 21608번: 상어 초등학교 (0) | 2022.12.19 |
[백준]JAVA - 20055번: 컨베이어 벨트 위의 로봇 (0) | 2022.12.14 |