본문 바로가기
Problem Solving/BOJ

[백준] 15683번 - 감시

by 테리는당근을좋아해 2020. 3. 16.

문제 >

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다.

 

 

1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할 수 있다.

CCTV는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다. 사무실에는 벽이 있는데, CCTV는 벽을 통과할 수 없다. CCTV가 감시할 수 없는 영역은 사각지대라고 한다.

CCTV는 회전시킬 수 있는데, 회전은 항상 90도 방향으로 해야 하며, 감시하려고 하는 방향이 가로 또는 세로 방향이어야 한다.

 

 

지도에서 0은 빈 칸, 6은 벽, 1~5는 CCTV의 번호이다. 위의 예시에서 1번의 방향에 따라 감시할 수 있는 영역을 '#'로 나타내면 아래와 같다.

 

 

CCTV는 벽을 통과할 수 없기 때문에, 1번이 → 방향을 감시하고 있을 때는 6의 오른쪽에 있는 벽을 감시할 수 없다.

 

 

위의 예시에서 감시할 수 있는 방향을 알아보면 아래와 같다.

 

 

CCTV는 CCTV를 통과할 수 있다. 아래 예시를 보자.

 

 

위와 같은 경우에 2의 방향이 ↕ 3의 방향이 ←와 ↓인 경우 감시받는 영역은 다음과 같다.

 

 

사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.

 

입력 >

첫째 줄에 사무실의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 8)

둘째 줄부터 N개의 줄에는 사무실 각 칸의 정보가 주어진다. 0은 빈 칸, 6은 벽, 1~5는 CCTV를 나타내고, 문제에서 설명한 CCTV의 종류이다. 

CCTV의 최대 개수는 8개를 넘지 않는다.

 

출력 >

첫째 줄에 사각 지대의 최소 크기를 출력한다.

 

해결방법 > 

DFS(깊이우선탐색) 알고리즘으로 각 CCTV의 방향을 설정했을 때 나올 수 있는 모든 경우의 수를 찾고 그 중 최소의 사각지대를 출력한다.

 

사무실에 대한 정보를 2차원 배열로 저장할 때, CCTV에 대한 좌표값과 번호를 저장한다.

 

저장된 CCTV를 하나씩 가능한 모든 경우에 따라 설치해본다.

 

각 CCTV의 번호에 따라 가능한 경우는 아래와 같다.

 

1번 CCTV > 동 / 서 / 남 / 북 (4 가지)

 

2번 CCTV > 동 - 서 / 남 - 북 (2 가지)

 

3번 CCTV > 북 - 동 / 동 - 남 / 남 - 서 / 서 - 북 (4 가지)

 

4번 CCTV > 서 - 북 - 동 / 북 - 동 - 남 / 동 - 남 - 서 / 남 - 서 - 북 (4 가지)

 

5번 CCTV > 동 - 서 - 남 - 북 (1 가지)

 

각 CCTV마다 한 가지 경우를 선택해 깊이우선탐색을 하고 마지막 CCTV를 선택했을 때 사각지대의 수를 구한다.

 

모든 가능한 경우를 탐색했을 때 사각지대의 최소값을 출력한다.

 

아래의 두 코드는 사실 메모리 사용량이나 시간에 차이는 없는데

 

단지 첫 번째 코드길이가 다른 분들이 제출한거에 비해 몇 배는 긴 거 같아서

 

다시 작성한 게 두 번째 코드.... 

 

되추적 알고리즘을 함께 사용하는 방법도 있는 거 같다.

 

이 문제는 다시 한 번 풀어봐야겠다

 

[JAVA]

package baekjoon;

import java.util.*;

public class BOJ_15683 {
	static int[][] map;
	static ArrayList<Node> camera;
	static int n;
	static int m;
	static int min;
	
	public static class Node{
		int x;
		int y;
		int k;
		
		Node(int x, int y, int k){
			this.x = x;
			this.y = y;
			this.k = k;
		}
	}
	
	public static void see(int x, int y, int dx, int dy, int[][] v) {
		int nx = x + dx;
		int ny = y + dy;
		
		while(nx >= 0 && ny >= 0 && nx < n && ny < m && map[nx][ny] != 6) {
			v[nx][ny] = 1;
			nx += dx;
			ny += dy;
		}
	}
	
	public static void dfs(Node node, int flag, int[][] v, int idx) {
		int[][] visit = new int[n][m];
		int x = node.x;
		int y = node.y;
		int k = node.k;
		
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				visit[i][j] = v[i][j];
			}
		}
		visit[x][y] = 1;
		
		if(k == 1) {
			if(flag == 0) {
				see(x, y, -1, 0, visit);
			}
			else if(flag == 1) {
				see(x, y, 0, 1, visit);
			}
			else if(flag == 2) {
				see(x, y, 1, 0, visit);
			}
			else {
				see(x, y, 0, -1, visit);
			}
		}
		else if(k == 2){
			if(flag == 0) {
				see(x, y, 0, -1, visit);
				see(x, y, 0, 1, visit);
			}
			else {
				see(x, y, -1, 0, visit);
				see(x, y, 1, 0, visit);
			}
		}
		else if(k == 3) {
			if(flag == 0) {
				see(x, y, -1, 0, visit);
				see(x, y, 0, 1, visit);
			}
			else if(flag == 1) {
				see(x, y, 0, 1, visit);
				see(x, y, 1, 0, visit);
			}
			else if(flag == 2) {
				see(x, y, 1, 0, visit);
				see(x, y, 0, -1, visit);
			}
			else {
				see(x, y, 0, -1, visit);
				see(x, y, -1, 0, visit);
			}
		}
		else if(k == 4) {
			if(flag == 0) {
				see(x, y, 0, -1, visit);
				see(x, y, -1, 0, visit);
				see(x, y, 0, 1, visit);
			}
			else if(flag == 1) {
				see(x, y, -1, 0, visit);
				see(x, y, 0, 1, visit);
				see(x, y, 1, 0, visit);
			}
			else if(flag == 2) {
				see(x, y, 0, 1, visit);
				see(x, y, 1, 0, visit);
				see(x, y, 0, -1, visit);
			}
			else {
				see(x, y, 1, 0, visit);
				see(x, y, 0, -1, visit);
				see(x, y, -1, 0, visit);
			}
		}
		else {
			see(x, y, -1, 0, visit);
			see(x, y, 0, 1, visit);
			see(x, y, 1, 0, visit);
			see(x, y, 0, -1, visit);
		}
		
		if(idx == camera.size()) {
			int cnt = 0;
			for(int i = 0; i < n; i++) {
				for(int j = 0; j < m; j++) {
					if(map[i][j] != 6 && visit[i][j] == 0) {
						cnt++;
					}
				}
			}
			min = Math.min(cnt, min);
			return;
		}
		node = camera.get(idx);
		k = node.k;
		
		if(k == 1 || k == 3 || k == 4) {
			dfs(node, 0, visit, idx+1);
			dfs(node, 1, visit, idx+1);
			dfs(node, 2, visit, idx+1);
			dfs(node, 3, visit, idx+1);
		}
		else if(k == 2) {
			dfs(node, 0, visit, idx+1);
			dfs(node, 1, visit, idx+1);
		}
		else {
			dfs(node, 0, visit, idx+1);
		}
		
	}
	
	public static void init() {
		int[][] visit = new int[n][m];
		Node node = camera.get(0);
		int k = node.k;
		if(k == 1 || k == 3 || k == 4) {
			dfs(node, 0, visit, 1);
			dfs(node, 1, visit, 1);
			dfs(node, 2, visit, 1);
			dfs(node, 3, visit, 1);
		}
		else if(k == 2) {
			dfs(node, 0, visit, 1);
			dfs(node, 1, visit, 1);
		}
		else {
			dfs(node, 0, visit, 1);
		}
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		map = new int[n][m];
		min = 0;
		camera = new ArrayList<>();
		
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				map[i][j] = sc.nextInt();
				if(map[i][j] >= 1 && map[i][j] <= 5)
					camera.add(new Node(i, j, map[i][j]));
				if(map[i][j] == 0)
					min++;
			}
		}
		if(camera.size() > 0) init();
		
		System.out.println(min);
	}
}

 

package baekjoon;

import java.util.*;

public class BOJ_15683_2 {
	static int n;
	static int m;
	static int[][] map;
	static ArrayList <Camera> list = new ArrayList<>();
	static int min = 0;
	static int[] dx = {-1, 0, 1, 0};
	static int[] dy = {0, 1, 0, -1};
	static int[][] one = {{0}, {1}, {2}, {3}};
	static int[][] two = {{0, 2}, {1, 3}};
	static int[][] three = {{0, 1}, {1, 2}, {2, 3}, {3, 0}};
	static int[][] four = {{0, 1, 2}, {1, 2, 3}, {2, 3, 0}, {3, 0, 1}};
	static int[][] five = {{0, 1, 2, 3}};
	
	public static class Camera{
		int x;
		int y;
		int num;
		
		Camera(int x, int y, int num){
			this.x = x;
			this.y = y;
			this.num = num;
		}
	}
	
	public static void set(Camera c, int idx, int flag, int[][] num, int[][] v) {
		int[][] visit = new int[n][m];
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				visit[i][j] = v[i][j];
			}
		}
		visit[c.x][c.y] = 1; 
		for(int i = 0; i < num[flag].length; i++) {
			int nx = c.x + dx[num[flag][i]];
			int ny = c.y + dy[num[flag][i]];
			
			while(nx >= 0 && ny >= 0 && nx < n && ny < m && map[nx][ny] != 6) {
				visit[nx][ny] = 1;
				nx += dx[num[flag][i]];
				ny += dy[num[flag][i]];
			}
		}
		
		classify(idx+1, visit);
	}
	
	public static void classify(int idx, int[][] v) {
		if(idx == list.size()) {
			int cnt = 0;
			for(int i = 0; i < n; i++) {
				for(int j = 0; j < m; j++) {
					if(map[i][j] != 6 && v[i][j] == 0)
						cnt++;
				}
			}
			min = Math.min(min, cnt);
			return;
		}
		Camera c = list.get(idx);
		int[][] visit = new int[n][m];
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				visit[i][j] = v[i][j];
			}
		}
		
		switch(c.num) {
		case 1:
			for(int i = 0; i < 4; i++) {
				set(c, idx, i, one, visit);
			}
			break;
		case 2:
			for(int i = 0; i < 2; i++) {
				set(c, idx, i, two, visit);
			}
			break;
		case 3:
			for(int i = 0; i < 4; i++) {
				set(c, idx, i, three, visit);
			}
			break;
		case 4:
			for(int i = 0; i < 4; i++) {
				set(c, idx, i, four, visit);
			}
			break;
		case 5:
			set(c, idx, 0, five, visit);
			break;
		}
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		map = new int[n][m];
		int[][] visit = new int[n][m];
		
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				map[i][j] = sc.nextInt();
				
				if(map[i][j] >= 1 && map[i][j] <= 5) {
					list.add(new Camera(i, j, map[i][j]));
				}
				
				if(map[i][j] == 0) min++;
			}
		}
		if(list.size() > 0) classify(0, visit);	
		System.out.println(min);
	}
}

 

댓글