본문 바로가기

알고리즘/SW 역량 테스트

[15683] 감시

반응형

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

 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다. 1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할

www.acmicpc.net


import java.util.Scanner;
import java.util.ArrayList;

class Main {

	static int N, M, L, answer = 99999999;
	static int[][] arr, map;
	static ArrayList<CCTV> list = new ArrayList<CCTV>();
	static int[] before, after, temp;
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		M = sc.nextInt();
		arr = new int[N][M];
		map = new int[N][M];
		before = new int[6];
		
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				arr[i][j] = sc.nextInt();
				if(arr[i][j] == 1) list.add(new CCTV(i, j, 1));
				if(arr[i][j] == 2) list.add(new CCTV(i, j, 2));
				if(arr[i][j] == 3) list.add(new CCTV(i, j, 3));
				if(arr[i][j] == 4) list.add(new CCTV(i, j, 4));
				if(arr[i][j] == 5) list.add(new CCTV(i, j, 5));
			}
		}
		
		L = list.size();
		temp = new int[L];
		copy();
		if(L==0) {
			System.out.println(calc());
			return;
		}
		
		for(int i=0; i<4; i++) {
			temp[0] = i+1;
			combination(i, 0);
		}
		
		combination(0, 0);
		
		System.out.println(answer);
		
	}
	
	public static void combination(int start, int depth) {
		if(depth == L-1) {
			copy();
			for(int i=0; i<L; i++) {
				CCTV c = list.get(i);
				spread(c.x, c.y, c.type, temp[i]);
			}
		
			answer = Math.min(calc(), answer);
			
			return;
		} 
		for(int i=start; i<4; i++) {
			temp[depth+1] = i+1;
			combination(i, depth+1);
		}
	}
	
	public static int calc() {
		int sum = 0;
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				if(map[i][j] == 0) sum++;
			}
		}
		return sum;
	}
	
	public static void spread(int x, int y, int type, int dir) {
		
		if(type == 1) {
			if(dir == 1) DFS(x, y, type, 1);
			if(dir == 2) DFS(x, y, type, 2);
			if(dir == 3) DFS(x, y, type, 3);
			if(dir == 4) DFS(x, y, type, 4);
		} else if(type == 2) {
			if(dir == 1) {
				DFS(x, y, type, 1);
				DFS(x, y, type, 2);
			}
			if(dir == 2) {
				DFS(x, y, type, 3);
				DFS(x, y, type, 4);
			}
			if(dir == 3) {
				DFS(x, y, type, 1);
				DFS(x, y, type, 2);
			}
			if(dir == 4) {
				DFS(x, y, type, 3);
				DFS(x, y, type, 4);
			}
			
		} else if(type == 3) {
			if(dir == 1) {
				DFS(x, y, type, 1);
				DFS(x, y, type, 4);
			}
			if(dir == 2) {
				DFS(x, y, type, 2);
				DFS(x, y, type, 4);
			}
			if(dir == 3) {
				DFS(x, y, type, 2);
				DFS(x, y, type, 3);
			}
			if(dir == 4) {
				DFS(x, y, type, 1);
				DFS(x, y, type, 3);
			}
		} else if(type == 4) {
			if(dir == 1) {
				DFS(x, y, type, 1);
				DFS(x, y, type, 2);
				DFS(x, y, type, 4);
			}
			if(dir == 2) {
				DFS(x, y, type, 2);
				DFS(x, y, type, 3);
				DFS(x, y, type, 4);
			}
			if(dir == 3) {
				DFS(x, y, type, 1);
				DFS(x, y, type, 2);
				DFS(x, y, type, 3);
			}
			if(dir == 4) {
				DFS(x, y, type, 1);
				DFS(x, y, type, 3);
				DFS(x, y, type, 4);
			}
		} else if(type == 5) {
			DFS(x, y, type, 1);
			DFS(x, y, type, 2);
			DFS(x, y, type, 3);
			DFS(x, y, type, 4);
		}
	}
			
	
	public static void DFS(int x, int y, int type, int dir) {
		
		int nx = x;
		int ny = y;
		
		if(dir == 1) {
			// 동	
			nx = x;
			ny = y+1;
		} else if(dir == 2) {
			// 서
			nx = x;
			ny = y-1;
			
		} else if(dir == 3) {
			// 남
			nx = x+1;
			ny = y;
			
		} else if(dir == 4) {
			// 북
			nx = x-1;
			ny = y;
		}
		
		if(!isInside(nx, ny)) return;
		if(map[nx][ny] == 6) return;
		if(map[nx][ny] == 0) map[nx][ny] = type;
		DFS(nx, ny, type, dir);
		
	}

	public static void copy() {
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				map[i][j] = arr[i][j];
			}
		}
	}

	public static boolean isInside(int x, int y) {
		if (x >= 0 && x < N && y >= 0 && y < M)
			return true;
		else
			return false;
	}
}

class CCTV {
	int x;
	int y;
	int type;

	CCTV(int x, int y, int type) {
		this.x = x;
		this.y = y;
		this.type = type;
	}
}

CCTV 를 90도씩 회전시켜서 사각지대의 최소크기를 구하는 브루트포스 문제입니다. 이 문제에서 핵심은 각 CCTV 마다  회전방향을 모두 탐색해야 합니다. 그래서 만약에 CCTV 개수가 3개 이고, 동서남북의 방향을 차례대로 1,2,3,4라고 가정한다면 111, 112, 113, 114, 121, 122, 123, 124 ... 444 까지 모든 조합의 수를 뽑아서 CCTV 마다 회전시켜서 사각지대를 계산하는 방법으로 해결했습니다.

[ 문제 풀이 ]

1. CCTV 의 번호는 1부터 5까지 있기 때문에 CCTV 클래스를 만들어서 좌표 두개와 CCTV 의 type 을 저장했습니다.

2. temp 배열은 CCTV의 개수만큼 길이로 정하여 CCTV 가 돌아갈 모든 방향의 번호를 저장할 배열입니다. 동서남북 순서로 1,2,3,4 를 저장합니다.

3. combination 함수로 모든 조합의 CCTV 방향을 정해주고 spread 함수를 통해서 CCTV가 회전하여 감시할 범위를 map에 표시해줍니다. 이 때 주의할점은 copy() 함수를 이용해서 계산하기 전에 매번 처음에 입력받았던 2차원 배열을 복사해줘야 한다는 점입니다.

4. spread() 를 할 때에는 CCTV가 있는 두개의 좌표와 CCTV 의 type, CCTV 가 돌아갈 방향을 입력받아서 DFS로 CCTV가 감시할 범위를 지도에 표시해줍니다.

5. 지도에 CCTV가 감시할 방향을 표시해줄 때 마다 calc() 함수를 이용하여 사각지대의 크기를 계산하고 최솟값을 answer에 저장해줍니다.

반응형

'알고리즘 > SW 역량 테스트' 카테고리의 다른 글

[SWEA] 5656. 벽돌 깨기  (0) 2019.10.22
[14891] 톱니바퀴  (0) 2019.10.19
[16235] 나무 재테크  (0) 2019.10.18
[15686] 치킨 배달  (0) 2019.10.17
[16234] 인구 이동  (0) 2019.10.16