문제 링크입니다: www.acmicpc.net/problem/20058
20058번: 마법사 상어와 파이어스톰
마법사 상어는 파이어볼과 토네이도를 조합해 파이어스톰을 시전할 수 있다. 오늘은 파이어스톰을 크기가 2N × 2N인 격자로 나누어진 얼음판에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c
www.acmicpc.net
기존 마법사 상어 문제들과 비슷한 유형이었습니다.
알고리즘은 아래와 같습니다.
1. 격자를 2^L * 2^L 크기의 부분 격자로 나눈 뒤 시계 방향으로 돌려줍니다. (rotate 메서드)
2. 파이어스톰을 시전합니다. (firestorm 메서드)
3. 1 ~ 2번 과정을 Q번 반복해줍니다.
4. 격자 내 모든 얼음 크기의 합을 구한 뒤 출력해주고 (getIceCnt 메서드)
5. 가장 큰 덩어리의 크기를 구한 뒤 출력해줍니다. (getLargestComponent 메서드)
이 문제에서의 핵심은 1번 알고리즘 즉, 2^L * 2^L 크기의 부분 격자로 나눈 뒤 회전시키는 알고리즘인데 해당 알고리즘은 아래와 같습니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void rotate(int y, int x, int l) | |
{ | |
int tempA[MAX][MAX]; | |
// 기존 2^L * 2^L 격자 복사 | |
for (int i = y; i < y + (1 << l); i++) | |
{ | |
for (int j = x; j < x + (1 << l); j++) | |
{ | |
tempA[i][j] = A[i][j]; | |
} | |
} | |
// 회전시키는 알고리즘 | |
for (int i = y; i < y + (1 << l); i++) | |
{ | |
for (int j = x; j < x + (1 << l); j++) | |
{ | |
A[j - x + y][y + (1 << l) - (i + 1) + x] = tempA[i][j]; | |
} | |
} | |
} |
전체 소스코드
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <queue> | |
#include <algorithm> | |
using namespace std; | |
const int MAX = 64; | |
typedef struct | |
{ | |
int y, x; | |
} Coord; | |
typedef struct | |
{ | |
int y, x; | |
} Dir; | |
Dir moveDir[4] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} }; | |
int N; | |
int A[MAX][MAX]; | |
bool visited[MAX][MAX]; | |
void rotate(int y, int x, int l) | |
{ | |
int tempA[MAX][MAX]; | |
for (int i = y; i < y + (1 << l); i++) | |
{ | |
for (int j = x; j < x + (1 << l); j++) | |
{ | |
tempA[i][j] = A[i][j]; | |
} | |
} | |
for (int i = y; i < y + (1 << l); i++) | |
{ | |
for (int j = x; j < x + (1 << l); j++) | |
{ | |
A[j - x + y][y + (1 << l) - (i + 1) + x] = tempA[i][j]; | |
} | |
} | |
} | |
void fireStorm(void) | |
{ | |
queue<Coord> q; | |
for (int y = 0; y < (1 << N); y++) | |
{ | |
for (int x = 0; x < (1 << N); x++) | |
{ | |
if (A[y][x] == 0) | |
{ | |
continue; | |
} | |
int adjacentIceCnt = 0; | |
for (int k = 0; k < 4; k++) | |
{ | |
int nextY = y + moveDir[k].y; | |
int nextX = x + moveDir[k].x; | |
if (nextY < 0 || nextY >= (1 << N) || nextX < 0 || nextX >= (1 << N)) | |
{ | |
continue; | |
} | |
if (A[nextY][nextX]) | |
{ | |
adjacentIceCnt++; | |
} | |
} | |
if (adjacentIceCnt < 3) | |
{ | |
q.push({ y, x }); | |
} | |
} | |
} | |
while (!q.empty()) | |
{ | |
int y = q.front().y; | |
int x = q.front().x; | |
q.pop(); | |
A[y][x]--; | |
} | |
} | |
int getIceSum(void) | |
{ | |
int result = 0; | |
for (int i = 0; i < (1 << N); i++) | |
{ | |
for (int j = 0; j < (1 << N); j++) | |
{ | |
result += A[i][j]; | |
} | |
} | |
return result; | |
} | |
int BFS(int y, int x) | |
{ | |
queue<Coord> q; | |
q.push({ y, x }); | |
visited[y][x] = true; | |
int cnt = 0; | |
while (!q.empty()) | |
{ | |
int curY = q.front().y; | |
int curX = q.front().x; | |
q.pop(); | |
cnt++; | |
for (int k = 0; k < 4; k++) | |
{ | |
int nextY = curY + moveDir[k].y; | |
int nextX = curX + moveDir[k].x; | |
if (nextY < 0 || nextY >= (1 << N) || nextX < 0 || nextX >= (1 << N)) | |
{ | |
continue; | |
} | |
if (visited[nextY][nextX] || A[nextY][nextX] == 0) | |
{ | |
continue; | |
} | |
visited[nextY][nextX] = true; | |
q.push({ nextY, nextX }); | |
} | |
} | |
return cnt; | |
} | |
int getLargentComponent(void) | |
{ | |
int result = 0; | |
for (int y = 0; y < (1 << N); y++) | |
{ | |
for (int x = 0; x < (1 << N); x++) | |
{ | |
if (visited[y][x] || A[y][x] == 0) | |
{ | |
continue; | |
} | |
result = max(result, BFS(y, x)); | |
} | |
} | |
return result; | |
} | |
int main(void) | |
{ | |
ios_base::sync_with_stdio(0); | |
cin.tie(0); | |
int Q; | |
cin >> N >> Q; | |
for (int i = 0; i < (1 << N); i++) | |
{ | |
for (int j = 0; j < (1 << N); j++) | |
{ | |
cin >> A[i][j]; | |
} | |
} | |
for (int q = 0; q < Q; q++) | |
{ | |
int L; | |
cin >> L; | |
for (int y = 0; y < (1 << N); y += (1 << L)) | |
{ | |
for (int x = 0; x < (1 << N); x += (1 << L)) | |
{ | |
rotate(y, x, L); | |
} | |
} | |
fireStorm(); | |
} | |
cout << getIceSum() << "\n"; | |
cout << getLargentComponent() << "\n"; | |
return 0; | |
} |


개발환경:Visual Studio 2017
지적, 조언, 질문 환영입니다! 댓글 남겨주세요~
반응형
'알고리즘 > BOJ' 카테고리의 다른 글
백준 2953번 나는 요리사다 (0) | 2021.05.05 |
---|---|
백준 21611번 마법사 상어와 블리자드 (0) | 2021.05.03 |
백준 21638번 SMS from MCHS (0) | 2021.05.02 |
BOJ 21633번 Bank Transfer (0) | 2021.05.02 |
백준 21631번 Checkers (0) | 2021.05.02 |