[C++]백준20056번 마법사 상어와 파이어볼
문제는 다음과 같다.
오늘은 백준20056번 마법사 상어와 파이어볼 문제를 풀어보도록 하자. 작년 하반기 S전자 기출문제로 예전에 나온 기출과 비슷한 유형의 문제다. 우선 fire_ball벡터로 파이어볼의 갯수와 정보들을 수집한다.
그 후 fire_ball_move 함수로 파이어볼의 움직임을 처리하는데, 여기서 중요한 개념인 Modulation 연산이 나온다. S전자의 단골유형 중 하나로써 꼭 익히고 가야한다. 만일 모듈레이션을 안할 경우, 즉 하나하나 계산을 한다면 시간초과가 날 것이다.
파이어볼의 움직임 연산이 끝나면 연산이 끝난 파이어볼은 벡터에서 빼준다. 그 후 처리된 파이어볼을 3차원 벡터에 push를 해준다.
fire_ball_check 함수에선 파이어볼이 2개 이상 들어간 것을 체크해준다. 만일 2개이상 들어가지 않았다면 그냥 fire_ball 벡터에 넣어주고 2개 이상이라면 문제 조건에 나온대로 처리를 해준다.
문제에 적힌대로 구현하면 답을 찾을 수 있는 문제였다.
[코드]
/*
1. fire_ball에 담는다.
2. 모두 움직이고 map에 넣어서 체크
3. 체크 후 다 빼고 fire_ball에 넣기
4. K--
*/
#include <iostream>
#include <vector>
using namespace std;
struct info {
int m;//질량
int s;//속력
int d;//방향
};
struct more_info {
int r_m;//행
int c_m;//열
int m_m;//질량
int s_m;//속력
int d_m;//방향
};
vector<info>map[51][51];
vector<more_info>fire_ball;
int dir[8][2] = { {-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1} };
int N, M, K,a,b,c,d,e,answer = 0;
int sum() {
for (int i = 0; i < fire_ball.size(); i++)answer += fire_ball[i].m_m;
return answer;
}
void fire_ball_check() {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (map[i][j].size() >= 2) {//만약 파이어볼이 2개 이상?
int even_cnt = 0, odd_cnt = 0, m_cnt = 0, s_cnt = 0;
for (int k = 0; k < map[i][j].size(); k++) { //파이어볼이 있는 곳 처리
m_cnt += map[i][j][k].m;//질량합
s_cnt += map[i][j][k].s;//속력합
if (map[i][j][k].d % 2 == 0) {//만일 방향이 짝수?
even_cnt++;
}
else {//홀수?
odd_cnt++;
}
}
int check_m = m_cnt / 5;
int check_s = s_cnt / map[i][j].size();
if (check_m > 0) {
if (even_cnt == map[i][j].size() || odd_cnt == map[i][j].size()) { //만약 다 짝수 or 홀수
fire_ball.push_back({ i,j,check_m, check_s,0 });
fire_ball.push_back({ i,j,check_m, check_s,2 });
fire_ball.push_back({ i,j,check_m, check_s,4 });
fire_ball.push_back({ i,j,check_m, check_s,6 });
}
else {// 그게 아니면 ?
fire_ball.push_back({ i,j,check_m, check_s,1 });
fire_ball.push_back({ i,j,check_m, check_s,3 });
fire_ball.push_back({ i,j,check_m, check_s,5 });
fire_ball.push_back({ i,j,check_m, check_s,7 });
}
}
}
else if(map[i][j].size() == 1){ //파이어볼 하나
fire_ball.push_back({ i,j,map[i][j][0].m,map[i][j][0].s,map[i][j][0].d });
}
map[i][j].clear();
}
}
}
void fire_ball_move() {
for (int i = fire_ball.size() - 1; i >= 0; i--) {
//움직인다.
int my = fire_ball[i].r_m + dir[fire_ball[i].d_m][0] * fire_ball[i].s_m;
int mx = fire_ball[i].c_m + dir[fire_ball[i].d_m][1] * fire_ball[i].s_m;
//만약 경계를 넘었으면
if (my > N) {
my %= N;
}
if (my < 1) {
my = N - (abs(my) % N);
}
if (mx > N) {
mx %= N;
}
if (mx < 1) {
mx = N - (abs(mx) % N);
}
map[my][mx].push_back({ fire_ball[i].m_m, fire_ball[i].s_m, fire_ball[i].d_m });
}
fire_ball.clear();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> N >> M >> K;//맵크기, 파이어볼 갯수, 실행횟수
for (int i = 0; i < M; i++) {
cin >> a >> b >> c >> d >> e;
fire_ball.push_back({ a,b,c,d,e });
}
while (K--) {
fire_ball_move();
fire_ball_check();
}
cout << sum();
}