티스토리 뷰

반응형

www.acmicpc.net/problem/17142

 

17142번: 연구소 3

인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고

www.acmicpc.net

> 문제 설명

더보기

문제

인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고, 활성 상태인 바이러스는 상하좌우로 인접한 모든 빈 칸으로 동시에 복제되며, 1초가 걸린다. 승원이는 연구소의 바이러스 M개를 활성 상태로 변경하려고 한다.

연구소는 크기가 N×N인 정사각형으로 나타낼 수 있으며, 정사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽, 바이러스로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다. 활성 바이러스가 비활성 바이러스가 있는 칸으로 가면 비활성 바이러스가 활성으로 변한다.

예를 들어, 아래와 같이 연구소가 생긴 경우를 살펴보자. 0은 빈 칸, 1은 벽, 2는 바이러스의 위치이다.

2 0 0 0 1 1 0
0 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 0 0
0 0 0 2 0 1 1
0 1 0 0 0 0 0
2 1 0 0 0 0 2

M = 3이고, 바이러스를 아래와 같이 활성 상태로 변경한 경우 6초면 모든 칸에 바이러스를 퍼뜨릴 수 있다. 벽은 -, 비활성 바이러스는 *, 활성 바이러스는 0, 빈 칸은 바이러스가 퍼지는 시간으로 표시했다.

* 6 5 4 - - 2
5 6 - 3 - 0 1
4 - - 2 - 1 2
3 - 2 1 2 2 3
2 2 1 0 1 - -
1 - 2 1 2 3 4
0 - 3 2 3 4 *

시간이 최소가 되는 방법은 아래와 같고, 4초만에 모든 칸에 바이러스를 퍼뜨릴 수 있다.

0 1 2 3 - - 2
1 2 - 3 - 0 1
2 - - 2 - 1 2
3 - 2 1 2 2 3
3 2 1 0 1 - -
4 - 2 1 2 3 4
* - 3 2 3 4 *

연구소의 상태가 주어졌을 때, 모든 빈 칸에 바이러스를 퍼뜨리는 최소 시간을 구해보자.

입력

첫째 줄에 연구소의 크기 N(4 ≤ N ≤ 50), 놓을 수 있는 바이러스의 개수 M(1 ≤ M ≤ 10)이 주어진다.

둘째 줄부터 N개의 줄에 연구소의 상태가 주어진다. 0은 빈 칸, 1은 벽, 2는 바이러스를 놓을 수 있는 위치이다. 2의 개수는 M보다 크거나 같고, 10보다 작거나 같은 자연수이다.

출력

연구소의 모든 빈 칸에 바이러스가 있게 되는 최소 시간을 출력한다. 바이러스를 어떻게 놓아도 모든 빈 칸에 바이러스를 퍼뜨릴 수 없는 경우에는 -1을 출력한다.

 

풀이

 

틀린 풀이 1. 선택한 바이러스에 대해 bfs()를 할 때 끝까지 돌려주고(벽은 -1로 체크) 마지막에 남은 0 있는지 확인하는 방식으로 풀었는데

그럼 탐색 못하는 쪽 벽은 -1로 처리가 안되서 bfs해줄 때마다 벽은 초기화를 해줘야 했다. (효율 안좋을 것 같아서 안해봄)

 

틀린 풀이 2. 처음 인풋 받았을 때, 각 바이러스에 대해서 퍼질 수 있는 곳 정보 map를 만들어줬다.

그리고 조합했을 때, M개의 바이러스 map을 합치고 거기서 최대시간값을 구하면 될 것 같다고 생각했는데

합치는 게 제대로 안되고, 아마 '비활성 바이러스가 활성 바이러스 만날 때' 그 부분을 체크를 잘 못해준 것 같다.

 

바이러스 고를 수 있는 조합에 대해 골라준다. (combination 함수)

고른 바이러스 수(count)가 M이 됐다면 bfs 시작

 

-> bfs

queue에 선택한 바이러스 위치들을 넣어준다.

고른 바이러스 위치의 시간은 0 (tempMap 배열에 저장, visited정보로 사용)

bfs 돌리면서 빈칸인 곳을 탐색해줄 때 count 해서 초기맵의 빈칸 개수랑 같아질 때 return 한다.

 

#define MAXN 51
#define MAXM 11
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <string.h>
using namespace std;

int N, M;
int map[MAXN][MAXN];
vector<pair<int, int> > virus;
bool selected[MAXM] = {false, };
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int minTime = 987654321;
int blankCnt = 0;
int tempMap[MAXN][MAXN];

void initialize(){
    
    cin>>N>>M;
    
    for(int i=0; i<N; i++){
        for(int j=0; j<N; j++){
            cin>>map[i][j];

            if(map[i][j] == 2){
                map[i][j] = -2;
                virus.push_back({i, j});
            }
            else if(map[i][j] == 0) {
                blankCnt++;
            }
        }
    }
    
    memset(selected, false, sizeof(selected));
}

void bfs(){
    
    queue<pair<int, int>> q;
    int cnt = blankCnt;
    
    memset(tempMap, -1, sizeof(tempMap));
    
    for(int i=0; i<virus.size(); i++){
        if(selected[i] == true){
            pair<int, int> v = virus[i];
            q.push(v);
            tempMap[v.first][v.second] = 0;
        }
    }
    
    while(!q.empty()){
        int nowx = q.front().first;
        int nowy = q.front().second;
        q.pop();
        
        for(int i=0; i<4; i++){
            int nextx = nowx + dir[i][0];
            int nexty = nowy + dir[i][1];
            
            if(nextx>=0 && nextx<N && nexty>=0 && nexty<N){
                if(map[nextx][nexty] != 1 && tempMap[nextx][nexty] == -1){
                    q.push({nextx, nexty});
                    tempMap[nextx][nexty] = tempMap[nowx][nowy] + 1;
                    
                    if(map[nextx][nexty] == 0){
                        cnt--;
                    }
                    
                    if(cnt == 0 ){
                        minTime = min(minTime, tempMap[nextx][nexty]);
                        return;
                    }
                }
            }
        }
    }
    
    return;
}


void combination(int depth, int count){
    
    if(count == M){
        bfs();
        return;
    }
    
    for(int i=depth; i<virus.size(); i++){
        if(selected[i] == false){
            selected[i] = true;
            combination(i+1, count+1);
            selected[i] = false;
        }
    }
    
    return;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    initialize();
    if(blankCnt == 0){
        cout<<"0"<<"\n";
        return 0;
    }
    
    combination(0, 0);
    
    if(minTime == 987654321){
        cout<<"-1\n";
    }
    else{
        cout<<minTime<<"\n";
    }


    return 0;
}
반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
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
글 보관함