알고리즘/삼성SW역량테스트기출
[백준 20056번 - 마법사 상어와 파이어볼] C++ 풀이
Ompang
2021. 10. 18. 12:44
728x90
반응형
20056번.
'1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다'
이 말인 즉슨, 1행에서 범위 초과하여 0행으로 갔을때, N행에 놓아주고, 1열에서 범위를 초과하여 0열로 갔을 때 N열에 놓아라는 의미이다. 반대로, N행에 있다가 범위를 초과하여 N + 1행으로 가면, 다시 1행에 놓아준다.
로직은 문제에 쓰인 그대로 풀이해주면 된다.
나는 2차원 벡터에 파이어볼을 담고있는 큐를 담았다.
그리고 이동한 파이어볼을 new_map 에 담아주고, 검사하면서 2개 이상 파이어볼이 있으면 합친 다음 4개로 만들어 주었다. 이 때, 만약 질량이 0이라면 파이어볼을 없애준다.
k 번 이동 후에 남아있는 파이어볼 질량 총 합을 구해주면 된다.
#include <stdio.h>
#include <vector>
#include <queue>
#define MAX 51
using namespace std;
struct fireball {
int r;
int c;
int m; // 질량
int d; // 방향
int s; // 속력
};
int n, m, p;
int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};
int ans = 0;
int main() {
scanf("%d %d %d", &n, &m, &p);
vector<vector<queue<fireball>>> map;
vector<vector<queue<fireball>>> new_map;
map.assign(n + 1, vector<queue<fireball>>(n + 1));
new_map.assign(n + 1, vector<queue<fireball>>(n + 1));
for(int i = 0; i < m; ++i) {
fireball tmp;
scanf("%d %d %d %d %d", &tmp.r, &tmp.c, &tmp.m, &tmp.s, &tmp.d);
map[tmp.r][tmp.c].push(tmp);
}
for(int i = 0; i < p; ++i) {
// 파이어볼 이동
for(int j = 1; j <= n; ++j) {
for(int k = 1; k <= n; ++k) {
if (!map[j][k].empty()) {
int size = map[j][k].size();
for(int v = 0; v < size; ++v) {
int x = map[j][k].front().r;
int y = map[j][k].front().c;
// d방향으로 s번 만큼 이동
for(int u = 0; u < map[j][k].front().s; ++u) {
x = x + dx[map[j][k].front().d];
y = y + dy[map[j][k].front().d];
if (x > n)
x = 1;
if (y > n)
y = 1;
if (x < 1)
x = n;
if (y < 1)
y = n;
}
fireball tmp = map[j][k].front();
tmp.r = x;
tmp.c = y;
new_map[x][y].push(tmp);
map[j][k].pop();
}
}
}
}
// 2개 이상의 파이어볼이 있는 칸이 있다면
for(int j = 1; j <= n; ++j) {
for(int k = 1; k <= n; ++k) {
if (new_map[j][k].size() == 1) {
map[j][k] = new_map[j][k];
new_map[j][k].pop();
} else if (new_map[j][k].size() >= 2) {
// 같은 칸의 파이어볼을 하나로 합친다
int m_sum = 0;
int s_sum = 0;
int size = new_map[j][k].size();
bool isAllEven = false;
bool isAllOdd = false;
while(!new_map[j][k].empty()) {
m_sum += new_map[j][k].front().m;
s_sum += new_map[j][k].front().s;
if (new_map[j][k].front().d % 2 == 0) {
isAllEven = true;
} else {
isAllOdd = true;
}
new_map[j][k].pop();
}
// 파이어볼은 4개의 파이어볼로 나눈다.
// 나누어진 파이어볼의 질량은 1/5
// 속력은 속력합 / 합쳐진 파이어볼 갯수
// 합쳐지는 파이어볼의 방향이 모두 홀수 or 모두 짝수면 0, 2, 4, 6 아니면 1, 3, 5, 7
if (isAllEven == isAllOdd && m_sum / 5 > 0) {
for(int u = 0; u < 4; ++u) {
fireball fb;
fb.r = j;
fb.c = k;
fb.s = s_sum / size;
fb.d = u * 2 + 1;
fb.m = m_sum / 5;
map[j][k].push(fb);
}
} else if (isAllEven != isAllOdd && m_sum / 5 > 0) {
for(int u = 0; u < 4; ++u) {
fireball fb;
fb.r = j;
fb.c = k;
fb.s = s_sum / size;
fb.d = u * 2;
fb.m = m_sum / 5;
map[j][k].push(fb);
}
}
}
}
}
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
if (map[i][j].size() > 0) {
while(!map[i][j].empty()) {
ans += map[i][j].front().m;
map[i][j].pop();
}
}
}
}
printf("%d\n", ans);
}
728x90