Algorithm/그래프 탐색

BOJ#14502 연구소

밤이2209 2017. 4. 25. 17:20

BOJ#14502 연구소


* 문제

https://www.acmicpc.net/problem/14502


* 풀이

2017년 상반기 삼성 SW 역량평가 기출문제 입니다.

벽을 항상 3개 설치해서 안전영역의 최대값을 구해야 하는 문제입니다.
즉, 완전 탐색이 필요합니다. (모든 경우를 다 해봐야 최대값을 구할 수 있음)

저는 아래와 같이 풀어보았습니다.

1. 조합을 돌려서 Map에서 빈칸 3개를 선택한 후 벽으로 바꿔줍니다.

최대 8*8 맵에서 빈칸 3개를 선택할 때 경우의 수 = (64-2)C3
(바이러스가 최소 2개 있으므로)

2. 해당 Map에서 바이러스를 퍼뜨립니다.

3. (맵의 크기 - 바이러스의 수 - 벽의 수) 의 최대값을 갱신합니다.

4. 1~3 반복





* 나의 코드




import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
* BOJ#14502 연구소
* https://www.acmicpc.net/problem/14502
*/

public class Main {

static final int BLANK = 0;
static final int WALL = 1;
static final int VIRUS = 2;
static final int nADDWALL = 3;
static final int[] dRow = {0, -1, 0, 1};
static final int[] dCol = {-1, 0, 1, 0};

static int N, M;
static int[][] map = new int[9][9];
static int nWall = 0;
static int safetyMaxArea = -1;

public static void main(String[] args) throws IOException {

// input
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());

for (int i = 0; i < N; i++) {

st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {

map[i][j] = Integer.parseInt(st.nextToken());
if (map[i][j] == WALL) nWall++;
}
}

// solve
int[] wallPos = new int[nADDWALL];
combination(wallPos, 0, 0, N * M, nADDWALL);

System.out.println(safetyMaxArea);
}

static void combination(int[] arr, int depth, int target, int n, int k) {

if (depth == k) {

commitMap(arr);
findSafetyArea();
rollbackMap(arr);
return;
}

if (target == n) {

return;
}

// 벽을 세울 수 있는 위치에만
if (map[target / M][target % M] == BLANK) {

arr[depth] = target;
combination(arr, depth + 1, target + 1, n, k);
}
combination(arr, depth, target + 1, n, k);
}

static void findSafetyArea() {

boolean[][] visited = new boolean[N][M];
for (int i = 0; i < N; i++) {

Arrays.fill(visited[i], false);
}

int nVirusArea = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {

if (map[i][j] == VIRUS && !visited[i][j]) {

nVirusArea += dfs(i, j, visited);
}
}
}

safetyMaxArea = Math.max(safetyMaxArea, N * M - (nVirusArea + nWall + nADDWALL));
}

static int dfs(int row, int col, boolean[][] visited) {

visited[row][col] = true;

int ret = 1;
for (int i = 0; i < 4; i++) {

int nextRow = row + dRow[i];
int nextCol = col + dCol[i];

if (nextRow < 0 || nextRow >= N || nextCol < 0 || nextCol >= M) continue;

if (map[nextRow][nextCol] != WALL && !visited[nextRow][nextCol]) {

ret += dfs(nextRow, nextCol, visited);
}
}

return ret;
}

static void commitMap(int[] arr) {

for (int i = 0; i < nADDWALL; i++) {

int row = arr[i] / M;
int col = arr[i] % M;

map[row][col] = WALL;
}
}

static void rollbackMap(int[] arr) {

for (int i = 0; i < nADDWALL; i++) {

int row = arr[i] / M;
int col = arr[i] % M;

map[row][col] = BLANK;
}
}
}


'Algorithm > 그래프 탐색' 카테고리의 다른 글

BOJ#10429 QUENTO  (0) 2017.06.01
BOJ#1525 퍼즐  (4) 2017.05.04
BOJ#14500 테트로미노  (0) 2017.04.21
BOJ#1600 말이 되고픈 원숭이  (0) 2017.04.19
BOJ#2638 치즈  (0) 2017.04.14