https://www.acmicpc.net/problem/17142
문제 설명
1. 비활성 바이러스의 위치가 여러곳 주어진다.
2. 그 중에서 M개를 선택해서 확산 바이러스로 만들고, 바이러스의 확산을 시작한다.
(확산 바이러스는 비활성 바이러스를 만나면 그 비활성 바이러스를 확산 바이러스로 바꾼다)
3. 바이러스가 전부 퍼질 때까지 걸린 시간의 최솟값을 구하여라.
문제를 시작하기 전에 몇가지 표현을 잘 이해하고 들어가야한다.
먼저 문제가 구하라고 한 것은, 바이러스가 다 퍼질 때까지 걸린 최소 시간이다. 퍼지는 바이러스가 활성 바이러스여야 한다는 말은 없다.
테스트케이스를 좋게 주지 않았더라면 괴랄한 정답률을 보여주지 않았을까 생각한다.
아래쪽에 있는 테스트 케이스를 활용하면 대부분의 엣지 케이스에 대한 감을 잡을 수 있을 것이다.
[알고리즘]
1. 백트레킹을 활용해서 전체 바이러스 중에서 m개를 선택한다.
2. 선택한 m개의 바이러스를 큐에 넣고 BFS를 돌린다.
3. 빈칸과 비활성 바이러스가 있으면서 방문하지 않은 지점이면 바이러스를 확산시키고, 시간을 기록한다.
4. 시간이 얼마 걸렸는지 파악하기 위해 방문처리 배열 내에서 최댓값을 찾는다. 이 때 최댓값을 선택할 때 그 지점이 바이러스가 위치하고 있는 지점이라면 최댓값으로 보지 않는다.
마지막 테스트 케이스에서와 같이, 이미 바이러스로 채워져있는 곳은 사실 방문할 필요가 없었던 지점이다. 하지만 거쳐가면서 확산이 이루어져야 하기 때문에 일단 채택은 하고, 바이러스가 전체로 퍼지는 시간에는 영향을 끼치면 안되기 때문에 제외해준다.
5. 위에서 구한 최댓값(시간)의 최솟값을 답으로 정한다.
#include<iostream> #include<vector> #include<queue> #include<limits.h> using namespace std; int n, m, map[51][51], dis[51][51], arr[11], st = 0; //연구소 크기, 바이러스 개수 bool isused[11]; struct VIRUS { int r; int c; }; vector<VIRUS> v; queue<pair<int, int> > q; int dr[4] = { 0,0,1,-1 }; int dc[4] = { 1,-1,0,0 }; int res = INT_MAX; void bfs() { while (!q.empty()) { pair<int, int> cur = q.front(); q.pop(); for (int i = 0; i < 4; i++) { int nr = cur.first + dr[i]; int nc = cur.second + dc[i]; if (nr < 0 || nc < 0 || nr >= n || nc >= n) continue; if (dis[nr][nc] >= 0 || map[nr][nc] == 1) continue; q.push({ nr, nc }); dis[nr][nc] = dis[cur.first][cur.second] + 1; } } } void init() { for(int i = 0 ; i < n ; i++) for (int j = 0; j < n; j++) dis[i][j] = -1; } bool isDone(){ for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (dis[i][j] == -1 && map[i][j] != 1) return false; } } return true; } void findMax() { int Max = 0; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if (Max < dis[i][j] && map[i][j] != 2) Max = dis[i][j]; if (res > Max) res = Max; } void func(int k) { if (k == m) { for (int i = 0; i < m; i++) { int r = v[arr[i]].r; int c = v[arr[i]].c; q.push({ r, c }); dis[r][c]++; } bfs(); if (isDone()) findMax(); init(); return; } if (k == 0) st = 0; for (int i = st; i < v.size(); i++) { if (!isused[i]) { arr[k] = i; st = i; isused[i] = true; func(k + 1); isused[i] = false; } } } int main(void) { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { cin >> map[i][j]; dis[i][j] = -1; if (map[i][j] == 2) { //바이러스 위치 저장 VIRUS tmp; tmp.r = i; tmp.c = j; v.push_back(tmp); } } func(0); if (res == INT_MAX) cout << -1 << '\n'; else cout << res; return 0; }
'알고리즘 문제 풀이 > 백준 온라인 저지' 카테고리의 다른 글
백준 17141번: 연구소 2 (C++) (0) | 2019.08.05 |
---|---|
백준 11050번: 이항 계수1 (C++) (0) | 2019.08.05 |
백준 17143번: 낚시왕 (C++) (0) | 2019.08.04 |
백준 16235번: 나무 재테크 (C++) (0) | 2019.07.30 |
백준 16234번: 인구 이동 (C++) (0) | 2019.07.26 |