상세 컨텐츠

본문 제목

2382. [모의 SW 역량테스트] 미생물 격리 (C++)

알고리즘/SWExpertAcademy

by 아리따운노을 2020. 5. 6. 20:17

본문

※ SW Expert 아카데미의 문제를 무단 복제하는 것을 금지합니다.


정사각형 구역 안에 K개의 미생물 군집이 있다.

이 구역은 가로 N개, 세로 N개, 총 N * N 개의 동일한 크기의 정사각형 셀들로 이루어져 있다.

미생물들이 구역을 벗어나는걸 방지하기 위해, 가장 바깥쪽 가장자리 부분에 위치한 셀들에는 특수한 약품이 칠해져 있다.

[Fig. 1]은 9개의 군집이 한 변이 7개의 셀로 이루어진 구역에 배치되어 있는 예이다.

가장자리의 빨간 셀은 약품이 칠해져 있는 셀이다.

 


[Fig. 1]

 

   ① 최초 각 미생물 군집의 위치와 군집 내 미생물의 수, 이동 방향이 주어진다. 약품이 칠해진 부분에는 미생물이 배치되어 있지 않다. 이동방향은 상, 하, 좌, 우 네 방향 중 하나이다.

   ② 각 군집들은 1시간마다 이동방향에 있는 다음 셀로 이동한다.

   ③ 미생물 군집이 이동 후 약품이 칠해진 셀에 도착하면 군집 내 미생물의 절반이 죽고, 이동방향이 반대로 바뀐다. 
       미생물 수가 홀수인 경우 반으로 나누어 떨어지지 않으므로, 다음과 같이 정의한다.
       살아남은 미생물 수 = 원래 미생물 수를 2로 나눈 후 소수점 이하를 버림 한 값
       따라서 군집에 미생물이 한 마리 있는 경우 살아남은 미생물 수가 0이 되기 때문에, 군집이 사라지게 된다,

   ④ 이동 후 두 개 이상의 군집이 한 셀에 모이는 경우 군집들이 합쳐지게 된다. 
       합쳐 진 군집의 미생물 수는 군집들의 미생물 수의 합이며, 이동 방향은 군집들 중 미생물 수가 가장 많은 군집의 이동방향이 된다. 
       합쳐지는 군집의 미생물 수가 같은 경우는 주어지지 않으므로 고려하지 않아도 된다.
     

M 시간 동안 이 미생물 군집들을 격리하였다. M시간 후 남아 있는 미생물 수의 총합을 구하여라.

시간에 지남에 따라 군집이 변하는 예를 보자.

[Fig. 2]은 최초 군집의 배치를 그림으로 표현한 것이다. 이는 예제 입력 1번과 동일하다. (N = 7, K = 9)
 


[Fig. 2]


1시간 후 [Fig. 3]과 같이 군집들이 이동한다.

A 군집은 약품이 칠해진 구역(가장 자리의 빨간 셀)로 이동하게 되어, 미생물 중3마리만 남고 나머지는 죽는다. 이동 방향은 상에서 하로 바뀐다.

D, E, F 군집은 모두 세로 위치 3, 가로 위치 3에 위치한 셀로 모이게 되며, 합쳐진 군집의 미생물 수는 8 + 14 + 3 = 25가 된다.

E 군집의 미생물 수가 가장 많기 때문에, 합쳐 진 군집의 이동 방향은 E 군집의 이동 방향인 상이 된다.

G, H 군집도 세로 위치 2, 가로 위치 5에 위치한 셀로 모이게 되며, 미생물 수는 108이 되고 이동 방향은 상이 된다.

 


[Fig. 3]



시작으로부터 2시간이 지났을 때, [Fig. 4]와 같이 군집들이 이동한다.

A, B 그룹은 이동 중 섞이지 않고 각 그룹의 이동 방향으로 움직이는데, B 그룹은 약품이 칠해진 셀로 이동하므로 미생물 수가 7에서 3으로 반감하고, 이동 방향이 상에서 하로 바뀐다.
 
 


[Fig. 4]



2시간이 지난 후, 남아 있는 미생물 수는 총 3 + 3 + 5 + 25 + 108 + 1 = 145이다.


[제약사항]

1. 시간제한 : 최대 50개 테스트 케이스를 모두 통과하는데, C/C++/Java 모두 5초

2. 구역의 모양은 정사각형으로 주어지며, 한 변의 셀의 개수 N은 5이상 100이하의 정수이다. (5 ≤ N ≤ 100)

3. 최초 배치되어 있는 미생물 군집의 개수 K는 5이상 1,000이하의 정수이다. (5 ≤ K ≤ 1,000)

4. 격리 시간 M은 1이상 1,000이하의 정수이다. (1 ≤ M ≤ 1,000)

5. 최초 약품이 칠해진 가장자리 부분 셀에는 미생물 군집이 배치되어 있지 않다.

6. 최초에 둘 이상의 군집이 동일한 셀에 배치되는 경우는 없다.

7. 각 군집 내 미생물 수는 1 이상 10,000 이하의 정수이다.

8. 군집의 이동방향은 상하좌우 4방향 중 한 방향을 가진다. (상: 1, 하: 2, 좌: 3, 우: 4)

9. 주어진 입력으로 진행하였을 때, 동일한 셀에 같은 미생물 수를 갖는 두 군집이 모이는 경우는 발생하지 않는다.

10.  각 군집의 정보는 세로 위치, 가로 위치, 미생물 수, 이동 방향 순으로 주어진다. 각 위치는 0번부터 시작한다.


[입력]

첫 줄에는 총 테스트 케이스의 개수 T가 주어진다.

그 다음 줄부터 T개의 테스트 케이스가 차례대로 주어진다.

각 테스트 케이스의 첫째 줄에는 구역의 한 변에 있는 셀의 개수 N, 격리 시간 M, 미생물 군집의 개수 K가 순서대로 주어지며, 다음 K줄에 걸쳐서 미생물 군집 K개의 정보가 주어진다.

미생물 군집의 정보는 세로 위치, 가로 위치, 미생물 수, 이동 방향 순으로 4개의 정수가 주어진다.


[출력]

테스트 케이스의 개수 만큼 T개의 줄에 각 테스트 케이스에 대한 답을 출력한다.

각 줄은 “#x”로 시작하고, 공백을 하나 둔 후 정답을 출력한다. (x는 테스트 케이스의 번호이며, 1번부터 시작한다.)

출력해야 할 정답은 M시간 후 남아 있는 미생물 수의 총 합이다.

 

 

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
#include <string.h>
#include <queue>
 
using namespace std;
 
int n,m,k,mx[] = {0,-1,1,0,0}, my[] = {0,0,0,-1,1};
long long ans;
int virus[100][100], dir[100][100];
queue<pair<intint> > q;
 
void solve()
{
    int Vtemp[100][100], Dtemp[100][100], MAX[100][100];
    queue<pair<intint> > temp;
    while(m--)
    {
        int qsize = q.size();
        memset(Vtemp, 0sizeof(Vtemp));
        memset(Dtemp, 0sizeof(Dtemp));
        memset(MAX, 0sizeof(MAX));
 
        while(qsize--)
        {
            int x = q.front().first;
            int y = q.front().second;
            q.pop();
 
            int nx = x + mx[dir[x][y]];
            int ny = y + my[dir[x][y]];
 
            if(MAX[nx][ny] < virus[x][y])
            {
                MAX[nx][ny] = virus[x][y];
                Dtemp[nx][ny] = dir[x][y];
            }
 
            if(Vtemp[nx][ny] == 0)
            {
                temp.push({nx,ny});
                q.push({nx,ny});
            }
            
            Vtemp[nx][ny] += virus[x][y];
            virus[x][y] = 0;
 
            if(nx==0 || ny==0 || nx==n-1 || ny==n-1)
            {
                Vtemp[nx][ny] /= 2;
                switch(Dtemp[nx][ny])
                {
                case 1:
                    Dtemp[nx][ny] = 2;
                    break;
                case 2:
                    Dtemp[nx][ny] = 1;
                    break;
                case 3:
                    Dtemp[nx][ny] = 4;
                    break;
                case 4:
                    Dtemp[nx][ny] = 3;
                    break;
                }
            }
        }
 
        while(!temp.empty())
        {
            int x = temp.front().first;
            int y = temp.front().second;
            temp.pop();
 
            virus[x][y] = Vtemp[x][y];
            dir[x][y] = Dtemp[x][y];
 
        }
    }
 
    while(!q.empty())
    {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        ans += virus[x][y];
    }
}
int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int tc, cnt,r,c,direction;
    cin>>tc;
    for(int t=1;t<=tc;t++)
    {
        memset(dir, 0sizeof(dir));
        memset(virus, 0sizeof(virus));
        ans = 0;
 
        cin>>n>>m>>k;
        for(int i=0;i<k;i++)
        {
            cin>>r>>c>>cnt>>direction;
            virus[r][c] = cnt;
            dir[r][c] = direction;
            q.push({r,c});
        }
        solve();
        cout<<'#'<<t<<' '<<ans<<'\n';
    }
    return 0;
}
 
cs

 

바이러스의 위치를 담고 있는 큐를 이용했다.

먼저 k개의 바이러스 위치와 방향을 기억하면서 큐에 위치를 집어 넣는다.

 

1. 일단 3개 행렬을 추가적으로 이용했는데 각각 바이러스 크기 기억, 바이러스 위치 기억, 가장 큰 바이러스 방향을 기억하기 위한 행렬이다. 

while문을 2중으로 썼는데 이렇게 하면 m시간 동안 바이러스를 움직일 수 있다.

 

2. 먼저 pop을 하면서 바이러스를 움직인다. 움직일 바이러스가 이미 있는 바이러스보다 크다면 방향을 현재 바이러스 방향으로 바꿔준다.

 

3. 바이러스가 한 군데로 모일때 여러 번 큐에 들어가는 것을 피하기 위해 다음 노드 크기가 0일 때만 큐에 넣어준다.

4. 바이러스가 이동하고 없어진 곳은 0

5. 빨간색 영역에 들어가면 바이러스 크기 1/2로 해주고 방향 전환

6. 바이러스 크기 기억한 행렬과 방향을 기억한 행렬과 현재 행렬 합쳐주기

 

7. m번 돌았다면 q에 남아 있는 노드를 찾으면서 ans에 해당 바이러스 크기 더해주기

 

 

 

 

 

관련글 더보기

댓글 영역