반응형
[모의 SW 역량테스트] 줄기세포배양
1. 이해하기
- 각 줄기 세포는 생명력이라는 수치를 가지고 있다.
- 초기 상태에서 줄기 세포들은 비활성 상태이며 생명력 수치가 X인 줄기 세포의 경우 X시간 동안 비활성 상태이고 X시간이 지나는 순간 활성 상태가 된다.
- 줄기 세포가 활성 상태가 되면 X시간 동안 살아있을 수 있으며 X시간이 지나면 세포는 죽게 된다.
- 세포가 죽더라도 소멸되는 것은 아니다.
- 활성화된 줄기 세포는 첫 1시간 동안 상, 하, 좌, 우 네 방향으로 동시에 번식 한다.
- 번식된 줄기 세포는 비활성 상태이다.
- 두 개 이상의 줄기 세포가 하나의 그리드 셀에 동시 번식하려고 하는 경우 생명력 수치가 높은 줄기 세포가 해당 셀을 차지한다.
- K시간 후 살아있는 줄기 세포(비활성+활성)의 총 개수를 구하는 문제.
- 시뮬레이션 문제.
2. 구현하기
-
이 문제는 배열의 크기가 주어져 있지 않지만 생각하면 최대 범위를 구할 수 있다.
- K+N+K, K+M+K이다.
- 이유는 하나의 세포가 양 옆으로 퍼져나가기 때문이다.
-
세포가 퍼져나가는 것을 구현한다.
- 세포가 퍼져나갈 수 없는 구역에 대해 알아보면, 셀에 세포가 죽어있거나 활성상태의 경우, 비활성상태이고 신규 세포가 아닌 경우이다.
- 세포가 비활성상태이고 신규 세포이면 다른 세포가 퍼져나갈 때, 크기를 비교해서 크기가 큰 세포가 해당 셀을 차지할 수 있다.
bool can_not_spread(int x, int y) { if(map[x][y].status == DEAD or map[x][y].status == ACTIVATE) return true; if(map[x][y].status == INACTIVATE and map[x][y].time != 0) return true; return false; } void spread(queue<Point>& q) { while(!q.empty()) { int x = q.front().x, y = q.front().y; q.pop(); for(int i = 0; i < 4; i++) { int nx = x+dx[i], ny = y+dy[i]; if(can_not_spread(nx,ny)) continue; if(map[nx][ny].status == INACTIVATE and map[nx][ny].time == 0) { if(map[nx][ny].life_time < map[x][y].life_time) { map[nx][ny].life_time = map[x][y].life_time; } } else { map[nx][ny] = {map[x][y].life_time,INACTIVATE,0}; } } } }
-
퍼져나갈 세포를 찾는다.
- 퍼져나갈 세포는 활성화 상태이고 지난 시간이 생명력 수치와 같을 때이다.
queue<Point> will_spread_cell() { queue<Point> ret; for(int i = 0; i < N+K; i++) { for(int j = 0; j < M+K; j++) { if(map[i][j].status == ACTIVATE and map[i][j].time == map[i][j].life_time) { ret.push({i,j}); } } } return ret; }
-
시간이 경과하는 것을 구현한다.
- 지난 시간이 자신의 생명력 수치와 같아질 때, 활성화 상태로 바꿔준다.
- 생명력 수치의 두 배가 되면, 그 세포는 죽은 상태로 바꾼다.
void time_pass() { for(int i = 0; i < N+K; i++) { for(int j = 0; j < M+K; j++) { if(map[i][j].status == NONE or map[i][j].status == DEAD) continue; map[i][j].time++; if(map[i][j].life_time == map[i][j].time) map[i][j].status = ACTIVATE; if(map[i][j].life_time*2 == map[i][j].time) map[i][j].status = DEAD; } } }
-
K시간까지 시뮬레이션을 한다.
void simulate() { for(int i = 0; i < K; i++) { queue<Point> spread_cell = will_spread_cell(); time_pass(); spread(spread_cell); } }
-
K시간이 지난 후, 비활성+활성 상태의 세포의 수를 구한다.
int count_cell() { int ret = 0; for(int i = 0; i < N+K; i++) { for(int j = 0; j < M+K; j++) { if(map[i][j].status == DEAD or map[i][j].status == NONE) continue; ret++; } } return ret; }
3. 전체 코드
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
#define NONE 0
#define DEAD 1
#define INACTIVATE 2
#define ACTIVATE 3
struct Point{
int x,y;
};
struct Cell{
int life_time,status,time;
};
Cell map[350][350];
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
int N,M,K;
bool can_not_spread(int x, int y) {
if(map[x][y].status == DEAD or map[x][y].status == ACTIVATE) return true;
if(map[x][y].status == INACTIVATE and map[x][y].time != 0) return true;
return false;
}
void spread(queue<Point>& q) {
while(!q.empty()) {
int x = q.front().x, y = q.front().y; q.pop();
for(int i = 0; i < 4; i++) {
int nx = x+dx[i], ny = y+dy[i];
if(can_not_spread(nx,ny)) continue;
if(map[nx][ny].status == INACTIVATE and map[nx][ny].time == 0) {
if(map[nx][ny].life_time < map[x][y].life_time) {
map[nx][ny].life_time = map[x][y].life_time;
}
} else {
map[nx][ny] = {map[x][y].life_time,INACTIVATE,0};
}
}
}
}
queue<Point> will_spread_cell() {
queue<Point> ret;
for(int i = 0; i < N+K; i++) {
for(int j = 0; j < M+K; j++) {
if(map[i][j].status == ACTIVATE and map[i][j].time == map[i][j].life_time) {
ret.push({i,j});
}
}
}
return ret;
}
void time_pass() {
for(int i = 0; i < N+K; i++) {
for(int j = 0; j < M+K; j++) {
if(map[i][j].status == NONE or map[i][j].status == DEAD) continue;
map[i][j].time++;
if(map[i][j].life_time == map[i][j].time) map[i][j].status = ACTIVATE;
if(map[i][j].life_time*2 == map[i][j].time) map[i][j].status = DEAD;
}
}
}
void simulate() {
for(int i = 0; i < K; i++) {
queue<Point> spread_cell = will_spread_cell();
time_pass();
spread(spread_cell);
}
}
int count_cell() {
int ret = 0;
for(int i = 0; i < N+K; i++) {
for(int j = 0; j < M+K; j++) {
if(map[i][j].status == DEAD or map[i][j].status == NONE) continue;
ret++;
}
}
return ret;
}
void input() {
memset(map,0,sizeof(map));
cin >> N >> M >> K;
for(int i = K/2; i < K/2+N; i++) {
for(int j = K/2; j < K/2+M; j++) {
int cell;
cin >> cell;
if(cell == 0) continue;
else {
map[i][j].life_time = cell;
map[i][j].status = INACTIVATE;
}
}
}
}
int main() {
int T;
cin >> T;
for(int t = 1; t <= T; t++) {
input();
simulate();
cout << '#' << t << ' ' << count_cell() << '\n';
}
return 0;
}
'알고리즘 > SW Expert Academy' 카테고리의 다른 글
[모의 SW 역량테스트] 5658. 보물상자 비밀번호 (0) | 2019.10.19 |
---|---|
[모의 SW 역량테스트] 5656. 벽돌 깨기 (0) | 2019.10.18 |
[모의 SW 역량테스트] 4008. 숫자 만들기 (0) | 2019.10.18 |
[모의 SW 역량테스트] 4012. 요리사 (0) | 2019.10.18 |
[모의 SW 역량테스트] 4013. 특이한 자석 (0) | 2019.10.17 |