문제
어른 상어가 마법사가 되었고, 파이어볼을 배웠다.
마법사 상어가 크기가 N×N인 격자에 파이어볼 M개를 발사했다. 가장 처음에 파이어볼은 각자 위치에서 이동을 대기하고 있다. i번 파이어볼의 위치는 (ri, ci), 질량은 mi이고, 방향은 di, 속력은 si이다. 위치 (r, c)는 r행 c열을 의미한다.
격자의 행과 열은 1번부터 N번까지 번호가 매겨져 있고, 1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다.
파이어볼의 방향은 어떤 칸과 인접한 8개의 칸의 방향을 의미하며, 정수로는 다음과 같다.
7 | 0 | 1 |
6 | 2 | |
5 | 4 | 3 |
마법사 상어가 모든 파이어볼에게 이동을 명령하면 다음이 일들이 일어난다.
- 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동한다.
- 이동하는 중에는 같은 칸에 여러 개의 파이어볼이 있을 수도 있다.
- 이동이 모두 끝난 뒤, 2개 이상의 파이어볼이 있는 칸에서는 다음과 같은 일이 일어난다.
- 같은 칸에 있는 파이어볼은 모두 하나로 합쳐진다.
- 파이어볼은 4개의 파이어볼로 나누어진다.
- 나누어진 파이어볼의 질량, 속력, 방향은 다음과 같다.
- 질량은 ⌊(합쳐진 파이어볼 질량의 합)/5⌋이다.
- 속력은 ⌊(합쳐진 파이어볼 속력의 합)/(합쳐진 파이어볼의 개수)⌋이다.
- 합쳐지는 파이어볼의 방향이 모두 홀수이거나 모두 짝수이면, 방향은 0, 2, 4, 6이 되고, 그렇지 않으면 1, 3, 5, 7이 된다.
- 질량이 0인 파이어볼은 소멸되어 없어진다.
마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 구해보자.
입력
첫째 줄에 N, M, K가 주어진다.
둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다.
서로 다른 두 파이어볼의 위치가 같은 경우는 입력으로 주어지지 않는다.
출력
마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 출력한다.
제한
- 4 ≤ N ≤ 50
- 0 ≤ M ≤ N2
- 1 ≤ K ≤ 1,000
- 1 ≤ ri, ci ≤ N
- 1 ≤ mi ≤ 1,000
- 1 ≤ si ≤ 1,000
- 0 ≤ di ≤ 7
구현해야할 조건
움직이는 파이어볼을 저장하고 2차원 vector에 다시 저장하여 2개 이상의 파이어볼이 있는 칸과, 없는 칸을 나눠 이동하는 파이어볼에 다시 저장을 하면 된다. 다만 질량이 합쳐진 파이어볼 질량의 합 / 5가 0이 되면 사라지기 때문에 이점을 유의해서 문제를 해결하도록 하자.
code
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<cstring>
#define MAX 51
using namespace std;
typedef struct {
int y;
int x;
int dir;
int massive;
int speed;
}Move;
typedef struct {
int dir;
int speed;
int massive;
}Fireball;
const int dx[8] = {0,1,1,1,0,-1,-1,-1};
const int dy[8] = { -1,-1,0,1,1,1,0,-1 };
const int even_num[4] = { 0,2,4,6 };
const int odd_num[4] = { 1,3,5,7 };
int n, m, k;
int r, c, mass, s, d;
vector<Fireball> v[MAX][MAX];
queue<Move> q;
int main()
{
cin >> n >> m >> k;
for (int i = 0; i < m; i++)
{
// y, x, massive, speed, direction
cin >> r >> c >> mass >> s >> d;
q.push({ r,c,d,mass,s });
}
//fireball move
while (k--)
{
while (!q.empty())
{
int y = q.front().y;
int x = q.front().x;
int d = q.front().dir;
int m = q.front().massive;
int s = q.front().speed;
q.pop();
//cout << y << " " << x << " " << m << " " << s << " " << d << endl;
int moduler = s % n; // speed % n
int nx = x + dx[d] * moduler;
int ny = y + dy[d] * moduler;
if (nx < 1) nx += n;
if (ny < 1) ny += n;
if (nx > n) nx -= n;
if (ny > n) ny -= n;
v[ny][nx].push_back({ d,s,m });
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (v[i][j].size() > 1)
{
int sum_massive = 0;
int sum_speed = 0;
bool odd = false;
bool even = false;
for (int k = 0; k < v[i][j].size(); k++)
{
sum_massive += v[i][j][k].massive;
sum_speed += v[i][j][k].speed;
if (v[i][j][k].dir % 2 == 0)
even = true;
else
odd = true;
}
if (sum_massive / 5 == 0) // massive is 0 equal disappear
{
v[i][j].clear();
continue;
}
if (even && !odd)
{
// only even
//y,x,d,m,s
for (int c = 0; c < 4; c++)
{
q.push({ i,j,even_num[c],sum_massive / 5, sum_speed / (int)v[i][j].size()});
}
}
else if (!even && odd)
{
// only odd
for (int c = 0; c < 4; c++)
{
q.push({ i,j,even_num[c],sum_massive / 5, sum_speed / (int)v[i][j].size() });
}
}
else if (even && odd)
{
// both
for (int c = 0; c < 4; c++)
{
q.push({ i,j,odd_num[c],sum_massive / 5, sum_speed / (int)v[i][j].size() });
}
}
}
else if(v[i][j].size() == 1)
{
//dir, speed, massive
q.push({ i,j,v[i][j][0].dir,v[i][j][0].massive,v[i][j][0].speed });
}
v[i][j].clear(); // clear condition essential!!!!
}
}
}
int sum = 0;
while (!q.empty())
{
int m = q.front().massive;
q.pop();
sum += m; // last plus values
}
cout << sum;
return 0;
}
code[vector로만 풀어보자 상세한 설명]
#include<iostream>
#include<vector>
#include<algorithm>
#define MAX 51
using namespace std;
typedef struct{
int y;
int x;
int massive;
int speed;
int dir;
}Fireball;
typedef struct{
int massive;
int speed;
int dir;
}Info;
const int dx[8] = {0,1,1,1,0,-1,-1,-1};
const int dy[8] = {-1,-1,0,1,1,1,0,-1}; // 8개의 방향 체크
int even_num[5] = {0,2,4,6};
int odd_num[5] = {1,3,5,7}; // 짝수 , 홀수 체크
int n,m,k;
vector<Fireball> v;
vector<Info> board[MAX][MAX];
int main()
{
cin >> n >> m >> k; // n : boardsize, m : fireball cnt, k : 실행횟수
for(int i = 0; i < m; i++)
{
int r,c,m,s,d; // r : y, c : x, m : massive, s : speed, d : direction;
cin >> r >> c >> m >> s >> d;
v.push_back({r,c,m,s,d}); // 이동해야할 fireball들 저장해둔 vector
}
while(k--) // k번 진행을 한다.
{
for(int i = 0; i < v.size(); i++) // vector에 저장된 fireball만큼
{
int y = v[i].y;
int x = v[i].x;
int massive = v[i].massive;
int speed = v[i].speed;
int dir = v[i].dir;
int mod = speed % n; // speed가 1000까지 주어지기 때문에, moduler는 필수이다.
int ny = y + dy[dir] * mod;
int nx = x + dx[dir] * mod;
/*
제한된 범위를 벗어나면 다시 돌아오는 조건이 있다.
n의 범위 만큼 추가되거나 빠지는 것을 생각!
*/
if(nx < 1) nx += n;
if(ny < 1) ny += n;
if(nx > n) nx -= n;
if(ny > n) ny -= n;
board[ny][nx].push_back({massive, speed, dir}); // fireball이 합쳐질 수 있기 때문에 vector를 사용해서 문제를 해결
}
v.clear(); // 꼭 해줘야하는 작업, queue를 사용한다면 사용하지 않아도 되지만, vector를 사용해서 문제를 풀기때문에 기억해야한다.
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(board[i][j].size() > 1) // 2개이상이라면, fireball을 합치고 나눠줘야하는 작업이 있다.
{
/*
홀수만, 짝수만인 경우와, 홀수 짝수 둘다 포함되는 경우 방향이 달라진다.
합쳐줘야할 것은 덩치,그리고 스피드
*/
bool odd = false;
bool even = false;
int fireball_size = (int)board[i][j].size();
int massive_sum = 0;
int speed_sum = 0;
for(int k = 0; k < board[i][j].size(); k++)
{
massive_sum += board[i][j][k].massive;
speed_sum += board[i][j][k].speed;
if(board[i][j][k].dir % 2 == 0) // even
even = true;
else // odd
odd = true;
}
massive_sum /= 5; // 5로 나눠주는 조건이 있는데 여기서
speed_sum /= fireball_size;
if(massive_sum == 0) // 덩치가 0이 된다면 넣어줄 필요가 없다.
{
board[i][j].clear(); // board또한 vector이기 때문에 지워주는 것 생각 이게 엣지케이스를 가를 예정
continue;
}
/*
speed는 0이 되어도 상관없나요? 나누는 것을 생각!
존재하는 수 만큼 나눠주는 것이기 때문에 1미만으로 떨어질 수 없습니다.
1, 1, 1, 1 이여도 4명으로 나눠도 1 이기 때문입니다.
*/
if(even && odd) // 짝수, 홀수 두개 다 들어가 있다면?
{
for(int c = 0; c < 4; c++)
v.push_back({i,j,massive_sum,speed_sum,odd_num[c]});
}
else if(!even && odd) // 짝수 하나만 또는 홀수 하나만 등장
{
for(int c = 0; c < 4; c++)
v.push_back({i,j,massive_sum,speed_sum,even_num[c]});
}
else if(even && !odd)
{
for(int c = 0; c < 4; c++)
v.push_back({i,j,massive_sum,speed_sum,even_num[c]});
}
}
else if(board[i][j].size() == 1) // 1개라면 그대로 들어가게 된다
{
v.push_back({i,j,board[i][j][0].massive, board[i][j][0].speed, board[i][j][0].dir});
}
board[i][j].clear(); // 벡터 전체 삭제해주는것 꼭 생각!
}
}
}
int res = 0; // 전체 과정이 끝났다면?
for(int i = 0; i < v.size(); i++)
res += v[i].massive;
cout << res;
return 0;
}
'PS > Samsung' 카테고리의 다른 글
[백준/c++] 21611 마법사 상어와 블리자드 (0) | 2022.02.23 |
---|---|
[백준/c++] 21610 마법사 상어와 비바라기 (0) | 2022.02.22 |
[백준/c++] 19238 스타트 택시 (0) | 2022.02.18 |
[백준/c++] 19237 어른 상어 (0) | 2022.02.17 |
[백준/c++] 19236 청소년 상어 (0) | 2022.02.17 |