본문 바로가기
BaekJoon/Gold

[BOJ/JAVA] 백준 15683 : 감시 (자바)

by HoonSikE 2022. 4. 16.
반응형
SMALL
문제 정보
  문제명   - 감시
  난이도   - 골드 IV
문제 번호 - 15683번

문제 링크

BOJ_G5_15683_감시

 

15683번: 감시

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

www.acmicpc.net


문제
스타트링크의 사무실은 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개를 넘지 않는다.

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

예제 입력/출력
예제 입력 예제 출력
4 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0
20
6 6
0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5
 15
6 6
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
 6
6 6
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 5 0 0
0 0 5 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
 2
1 7
0 1 2 3 4 5 6
 0
3 7
4 0 0 0 0 0 0
0 0 0 2 0 0 0
0 0 0 0 0 0 4
 0

알고리즘 분류
● 구현
● 브루트포스 알고리즘
● 시뮬레이션


소스코드
package Lv3_Gold;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
/**
 * @author HanHoon
 * @category 구현, 브루트포스 알고리즘, 시뮬레이션
 * https://www.acmicpc.net/problem/15683
 */
class CCTV {
	int Row;
	int Col;
	int Number;
	// 좌하우상
	int Direction;
	public CCTV(int row, int col, int number, int direction) {
		Row = row;
		Col = col;
		Number = number;
		Direction = direction;
	}
}
public class BOJ_G5_15683_감시 {
	static int N, M;
	static int result = Integer.MAX_VALUE;
	static int[][] map;
	static int[][] tmp;
	static ArrayList<CCTV> list = new ArrayList<>();
	// 좌하우상
	static int[] dRow = { 0, 1, 0,-1};
	static int[] dCol = {-1, 0, 1, 0};
	// 구역 내 사각지대 계산
	public static void calculate() {
		int count = 0;
		for (int i = 0; i < N; i++)
			for (int j = 0; j < M; j++)
				// 아직 복도인곳 == 사각지대
				if(tmp[i][j] == 0)
					count++;
		// 최소값 최신화
		result = Math.min(result, count);
	}
	// index 방향으로 check
	public static void checkFunction(int Row, int Col, int index){
		while(true) {
			Row += dRow[index];
			Col += dCol[index];
			// 범위에서 벗어나거나 벽을 만난다면 return;
			if(Row < 0 || Row >= N || Col < 0 || Col >= M || tmp[Row][Col] == 6) 
				return;
			// 탐지된 구역은 -1로 변경
			tmp[Row][Col] = -1;
		}
	}
	public static void checkBlindSpot(){
		// map을 사용하게 되면 값이 변해서 2번쨰 시도부터 꼬이게 되기때문에 임시값 사용
		for (int i = 0; i < N; i++)
			tmp[i] = map[i].clone();
		// 모든 CCTV에 대해 감시 실시
		for (CCTV cctv : list) {
			switch (cctv.Number) {
				// 1쪽 방향
				case 1:
					checkFunction(cctv.Row, cctv.Col, cctv.Direction);
					break;
				// 양 방향
				case 2:
					checkFunction(cctv.Row, cctv.Col, cctv.Direction);
					checkFunction(cctv.Row, cctv.Col, (cctv.Direction+2)%4);
					break;
				// 직각 방향
				case 3:
					for (int index = 0; index < 2; index++)
						checkFunction(cctv.Row, cctv.Col, (cctv.Direction+index)%4);
					break;
				// 앞, 좌우
				case 4:
					for (int index = 0; index < 3; index++)
						checkFunction(cctv.Row, cctv.Col, (cctv.Direction+index)%4);
					break;
				// 4방향
				case 5:
					for (int index = 0; index < 4; index++)
						checkFunction(cctv.Row, cctv.Col, (cctv.Direction+index)%4);
					break;
			}
		}
	}
	public static void checkCCTV(int count){
		// 모든 CCTV를 확인했으면 return;
		if(count == list.size()) {
			// 모든 CCTV에 대해 감시 실시
			checkBlindSpot();
			// 구역 내 사각지대 계산
			calculate();
			return;
		}
		// 현재 CCTV 방향 설정 후 재귀로 모든 방향에 대한 경우의수 실행
		CCTV cctv = list.get(count);
		// CCTV별 방향 설정 (기본방향은 0으로 설정되어있으므로 바로 재귀 실시)
		switch(cctv.Number){
			// 2: 2방향(좌우,하상)
			case 2:
				cctv.Direction = 0; checkCCTV(count+1);
				cctv.Direction = 1; checkCCTV(count+1);
				break;
			// 5: 1방향(좌하우상)
			case 5:
				cctv.Direction = 0; checkCCTV(count+1);
				break;
			// 1,3,4: 4방향(좌,하,우,상)
			default:
				cctv.Direction = 0; checkCCTV(count+1);
				cctv.Direction = 1; checkCCTV(count+1);
				cctv.Direction = 2; checkCCTV(count+1);
				cctv.Direction = 3; checkCCTV(count+1);
				break;
		}
	}
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		// NxM 크기의 사무실
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		// 사무실 데이터 입력 0:복도, 1~5:CCTV, 6:벽
		map = new int[N][M];
		tmp = new int[N][M];
		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());
				// CCTV 추가
				if(1 <= map[i][j] && map[i][j] <= 5)
					list.add(new CCTV(i, j, map[i][j], 0));
			}
		}
		checkCCTV(0);
		System.out.println(result);
		br.close();
	}
}

 


BaekJoon List
 

BaekJoon List

BOJ Start!! ● [BOJ] 백준 회원가입, 시작하는 법 ● [BOJ] 등급(티어) 및 Solved.AC 적용 ● [BOJ/JAVA] 백준 소스코드 제출 시 유의사항(자바) Bronze ● Bronze V  - ● Bronze IV  - ● Bronze III  -..

han-hoon.tistory.com


  

기회는 준비된 자에게 찾아온다.

 


 

반응형
LIST

댓글