PS/백준

[백준] 14502 연구소 (C++)

dong_gas 2021. 9. 5. 23:17
 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크

www.acmicpc.net

 solved.ac 클래스 4에 있는 문제이다. 문제를 읽으면서 새로 세울 수 있는 벽은 3개이고, 꼭 3개를 세워야 한다는 것을 보고 브루트포스를 통해 모든 경우를 봐야겠다고 생각했다. 벽을 3개만 세우는 경우의 수가 크지 않기 때문이다. 그 이후에는 바이러스가 퍼지게 되면 차지하는 넓이를 구해주었다. 모든 경우에 대해서 해당 작업을 한 뒤, 빈칸의 개수의 최댓값이 답이다.

 

 

 참고로, '[BOJ] 22953 도도의 음식준비' 문제와 비슷하다고 느꼈다. 22953번 도도의 음식 준비 문제도 C값이 5 이하이기 때문에 모든 경우를 보는 것이 어렵지 않았기 때문이다. 다른 점이라면, 22953번 문제는 (브루트포스+이분탐색)이고, 14502 연구소 문제는 (브루트포스+DFS)이다.

 


풀이

 우선, board에 연구소의 상태를 입력받는다. 이 때, 벽이 아닌 곳의 넓이(nowwall)를 계산해준다. 그 후에, solve함수에서 브루트포스 기법을 통해 모든 경우를 다 본다. 이 때, 벽을 3개 세우게 되므로 notwall 값은 3이 줄어든다. solve함수의 input값은 앞으로 설치해야 할 벽의 개수이다. 그 값이 0이면 벽을 모두 설치했다는 의미이다. 

 

벽을 모두 설치하였다면 dfs를 통해 문제를 해결한다. 전체 board를 탐색하면서 바이러스가 있는 곳이면 그 곳을 포함하여 dfs를 통해 바이러스가 퍼진 뒤의 넓이(virus)를 구한다. 그러면 (notwall-virus) 값이 안전한 영역의 넓이가 된다. (벽이 아닌 곳의 넓이 중 바이러스가 있는 넓이를 빼주었으므로)

 

이렇게 구한 notwall-virus값 중 가장 큰 값이 답이 된다.

 


코드

#include <iostream>
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;

ll n, m, notwall = 0, virus = 0; //notwall은 벽이 아닌 곳의 넓이,virus는 바이러스가 있는 곳의 넓이
ll board[9][9];
ll visited[9][9];
ll dx[4] = { 0,1,0,-1 };
ll dy[4] = { 1,0,-1,0 };
ll ans = -1;

void dfs(ll x, ll y) {
    for (ll i = 0; i < 4; i++) {
        ll nx = x + dx[i];
        ll ny = y + dy[i];
        if (nx >= 1 && ny >= 1 && nx <= n && ny <= m && !visited[nx][ny]) {
            if (board[nx][ny] == 0) {
                virus++;
                visited[nx][ny] = 1;
                dfs(nx, ny);
            }
        }
    }
}

void solve(ll wall) { //wall값은 앞으로 설치해야 할 벽의 개수
    if (wall == 0) {//벽 3개를 모두 설치한 경우
        memset(visited, 0, sizeof(visited)); //dfs하기 전, visited함수 0으로 초기화
        virus = 0;
        for (ll i = 1; i <= n; i++) {
            for (ll j = 1; j <= m; j++) {
                if (board[i][j] == 2 && !visited[i][j]) {
                    virus++;
                    dfs(i, j); //dfs를 통해 바이러스 퍼뜨리는 과정
                }
            }
        }
        ans = max(ans, notwall - virus);
        return;
    }
    else {//아직 벽을 3개 다 설치하지 못한 경우
        for (ll i = 1; i <= n; i++) {
            for (ll j = 1; j <= m; j++) {
                if (board[i][j] == 0) {
                    board[i][j] = 1; //빈칸이면 벽을 설치한다.
                    solve(wall - 1); //벽을 설치했으므로 cnt값을 1 줄여서 solve함수에 넣는다.
                    board[i][j] = 0; //벽을 다시 제거해준다.
                }
            }
        }
    }
}

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

    cin >> n >> m;
    for (ll i = 1; i <= n; i++) {
        for (ll j = 1; j <= m; j++) {
            cin >> board[i][j];
            if (board[i][j] != 1) notwall++; //벽이 아닌 영역의 넓이 계산
        }
    }

    notwall -= 3; //벽을 3개 세워야 하므로 3빼준다.
    solve(3); //벽을 3개 세워야 한다.

    cout << ans << endl;

    return 0;
}

'PS > 백준' 카테고리의 다른 글

[백준] 23247 Ten (C++)  (0) 2021.10.13
[백준] 1736 쓰레기 치우기 (C++)  (6) 2021.10.11
[백준] 2206 벽 부수고 이동하기 (C++)  (0) 2021.09.10
[백준] 15650 N과 M(2) (C++)  (0) 2021.09.10
[백준] 22953 도도의 음식 준비 (C++)  (0) 2021.09.01