일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 삼성코테
- dfs
- DP
- 임베디드 딥러닝
- 다이나믹프로그래밍
- 코테 문제
- DP문제
- 컴퓨팅사고
- bfs문제
- 영상처리
- 포스코 교육
- 자료구조
- sort
- MCU 딥러닝
- 코테
- 삼성역량테스트
- 코딩테스트
- TensorFlow Lite
- dfs문제
- tinyml
- BFS
- 포스코 ai 교육
- 삼성코딩테스트
- 초소형머신러닝
- tflite
- 알고리즘
- 포스코 AI교육
- 그리디
- 딥러닝
- 삼성역테
- Today
- Total
코딩뚠뚠
[삼성역량테스트] 20056 마법사 상어와 파이어볼 본문
풀이일시 : 2021-01-16
문제 :
어른 상어가 마법사가 되었고, 파이어볼을 배웠다.
마법사 상어가 크기가 N×N인 격자에 파이어볼 M개를 발사했다. 가장 처음에 파이어볼은 각자 위치에서 이동을 대기하고 있다. i번 파이어볼의 위치는 (ri, ci), 질량은 mi이고, 방향은 di, 속력은 si이다. 위치 (r, c)는 r행 c열을 의미한다.
격자의 행과 열은 1번부터 N번까지 번호가 매겨져 있고, 1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다.
파이어볼의 방향은 어떤 칸과 인접한 8개의 칸의 방향을 의미하며, 정수로는 다음과 같다.
마법사 상어가 모든 파이어볼에게 이동을 명령하면 다음이 일들이 일어난다.
- 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동한다.
- 이동하는 중에는 같은 칸에 여러 개의 파이어볼이 있을 수도 있다.
- 이동이 모두 끝난 뒤, 2개 이상의 파이어볼이 있는 칸에서는 다음과 같은 일이 일어난다.
- 같은 칸에 있는 파이어볼은 모두 하나로 합쳐진다.
- 파이어볼은 4개의 파이어볼로 나누어진다.
- 나누어진 파이어볼의 질량, 속력, 방향은 다음과 같다.
- 질량은 ⌊(합쳐진 파이어볼 질량의 합)/5⌋이다.
- 속력은 ⌊(합쳐진 파이어볼 속력의 합)/(합쳐진 파이어볼의 개수)⌋이다.
- 합쳐지는 파이어볼의 방향이 모두 홀수이거나 모두 짝수이면, 방향은 0, 2, 4, 6이 되고, 그렇지 않으면 1, 3, 5, 7이 된다.
- 질량이 0인 파이어볼은 소멸되어 없어진다.
마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 구해보자.
입력 :
첫째 줄에 N, M, K가 주어진다.
둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다.
서로 다른 두 파이어볼의 위치가 같은 경우는 입력으로 주어지지 않는다.
ex)
7 5 3
1 3 5 2 4
2 3 5 2 6
5 2 9 1 7
6 2 1 3 5
4 4 2 4 2
출력 :
마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 출력한다.
ex)
9
제한 :
- 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
풀이 :
차근차근히 꼼꼼히 읽고 풀어나가면 되는 시뮬레이션 문제이다. 복잡한 알고리즘이 들어있지않다.
- 파이어볼을 ball 형의 벡터로 선언했다. (struct ball : r c m s d)
- 같은 칸에 파이어볼이 두개 이상 존재할 경우에 합하고 뿌려줘야 하기 때문에, 판단하기 위해 map을 선언해주었다
- 파이어볼의 이동은 dr[] 과 dc[]로 구현했는데, 알고리즘문제를 좀 풀어봤다면 4방향을 찾는 bfs문제를 본적이 있을 것이다. 이와 같이 8방향으로 설정해주면 된다.
- 경우에 따라 방향을 나누어주는 것도 마찬가지로 나타낸다. st_0[], st_1[]
경우 1 : dr[st_0[i]]
경우 2 : dr[st_1[i]]
이와같이 혼합해서 사용할 수 있다.
코드를 보며, 주석을 보며 이해하자.
#define MAX 51
#include <iostream>
#include <vector>
#include <string.h> //memset 을 위해 사용
using namespace std;
int N, M, K;
struct ball { //ball의 형태를 구조체로 선언
int r;
int c;
int m;
int s;
int d;
};
vector<ball>fireball; //fireball은 ball의 형태
vector<ball>map[MAX][MAX]; //여러 값을 가질수 있다는 것을 내포한다. 값을 push하면 [MAX[MAX][i] 이기때문
int dr[] = { -1,-1,0,1,1,1,0,-1 };
int dc[] = { 0,1,1,1,0,-1,-1,-1 };
int st_0[] = {0,2,4,6};
int st_1[] = {1,3,5,7};
void move() { //이동해주고 map에 저장해주는것
memset(map, false, sizeof(map)); //들어올때마다 새로운 map을 만들어야한다.
for (int i = 0; i < fireball.size(); i++) {
int r = fireball[i].r;
int c = fireball[i].c;
int m = fireball[i].m;
int s = fireball[i].s;
int d = fireball[i].d;
int new_s = s % N; //속도(몇칸이나 이동할지에 대한 나머지연산)
int new_r = r + dr[d] * new_s;
int new_c = c + dc[d] * new_s;
if (new_r > N) //직접 그려보며 이해해보도록 하자. 없으면 안되는 조건이다.
new_r -= N;
if (new_r < 1)
new_r += N;
if (new_c > N)
new_c -= N;
if (new_c < 1)
new_c += N;
//아래와같이 해주면 fireball을 하나 더 생성해주는 것이기 때문에 안된다.
//fireball.push_back({ new_r,new_c,m,s,d });
fireball[i].r = new_r;
fireball[i].c = new_c;
map[new_r][new_c].push_back({ new_r,new_c,m,s,d });
}
}
void hap_spread() {
vector<ball>temp; //fireball의 바뀐값을 임시로 저장할 벡터 temp 생성
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
//합할것은 2개 이상일때부터 있을것이므로.
if (map[i][j].size() == 0)
continue;
if (map[i][j].size() == 1) {
temp.push_back(map[i][j][0]);
continue;
}
int odd = 0;
int even = 0;
int cnt = map[i][j].size();
int new_m = 0;
int new_s = 0;
for (int k = 0; k < cnt; k++) {
new_m += map[i][j][k].m;
new_s += map[i][j][k].s;
if (map[i][j][k].d % 2 == 0) { //짝수라면
even = 1;
}
else { //홀수이면
odd = 1;
}
}
new_m = new_m / 5;
new_s = new_s / cnt;
if (new_m == 0) // 내가 누락했던 부분이다. 꼭 써주도록하자.
continue;
if ((odd == 1)&&(even==1)) { //홀이던 짝이던 섞여있다면 1357
for (int k = 0; k < 4;k++) {
temp.push_back({ i,j,new_m,new_s,st_1[k] });
}
}
else { //하나만있다면
for (int k = 0; k < 4; k++) {
temp.push_back({ i,j,new_m,new_s,st_0[k] });
}
}
}
}
fireball = temp; //결국 fireball이 바뀐것이 나타나게 된다. map노필요
}
int main() {
cin >> N >> M >> K;
for (int k = 0; k < M; k++) {
int r, c, m, s, d;
cin >> r >> c >> m >> s >> d;
fireball.push_back({ r,c,m,s,d });
}
for (int i = 0; i < K; i++) {
move();
hap_spread();
}
int ans = 0;
for (int i = 0; i < fireball.size(); i++) {
ans += fireball[i].m; //파이어볼 질량의 합
}
cout << ans << endl;
return 0;
}
참고자료 : memset
'알고리즘 문제풀이 > 삼성역량테스트' 카테고리의 다른 글
[삼성역량테스트] 19238 스타트택시 (0) | 2021.01.25 |
---|---|
[삼성역량테스트] 20055 컨베이어 벨트 위의 로봇 (0) | 2021.01.18 |
[삼성역량테스트] 20057 마법사 상어와 토네이도 (0) | 2021.01.12 |
[삼성역량테스트] 14499 주사위 굴리기 (0) | 2021.01.03 |
[삼성역량테스트] 15683 감시 (0) | 2021.01.03 |