KimMinJun
Coding Note
KimMinJun
전체 방문자
오늘
어제
  • 분류 전체보기 (487)
    • ALGORITHM (11)
      • 정렬 (6)
      • 최단경로 (1)
      • 자료구조 (1)
      • 슬라이딩 윈도우 (1)
      • etc (2)
    • Git (5)
    • Web (24)
      • Vanilla JS (13)
      • TS (2)
      • React (7)
      • ETC (1)
    • React 공식문서 (번역, 공부) (11)
      • Quick Start (2)
      • Installation (0)
      • Describing the UI (9)
      • Adding Interactivity (0)
      • Managing State (0)
      • Escape Hatches (0)
    • Next.js 공식문서 (번역, 공부) (3)
      • Getting Started (2)
      • Building Your Application (1)
    • PS (432)
      • 백준 (187)
      • Programmers (105)
      • CodeUp (21)
      • STL (3)
      • 제코베 JS 100제 (50)
      • SWEA (0)
      • LeetCode (65)
    • IT (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 관리

공지사항

인기 글

태그

  • 백준
  • programmers
  • codeup
  • C
  • 수학
  • Level 1
  • tree
  • 제코베 JS 100제
  • C++
  • 문자열
  • 그래프
  • Level1
  • 정렬
  • LeetCode
  • recursion
  • 다이나믹 프로그래밍
  • Level 2
  • string
  • Level 0
  • js

최근 댓글

최근 글

hELLO · Designed By 정상우.
KimMinJun

Coding Note

PS/백준

백준 / 백트래킹 / 15683번 / 감시 / Java

2023. 7. 27. 15:46

< 문제 바로가기 >

 

15683번: 감시

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

www.acmicpc.net

 

package ps;

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

public class Main {
	// CCTV의 좌표와 번호가 담긴 클래스의 리스트
	private static ArrayList<Position> cctvList = new ArrayList<>();
	
	// 위쪽, 오른쪽, 아래쪽, 왼쪽
	private static int[] dr = { -1, 0, 1, 0 };
	private static int[] dc = { 0, 1, 0, -1 };
	// 위쪽:0, 오른쪽:1, 아래쪽:2, 왼쪽:3
	private static int[][] dir = {
			{}, // 0번 CCTV는 없으므로 비워둠 (padding)
			{1},
			{1, 3},
			{0, 1},
			{0, 1, 3},
			{0, 1, 2, 3}
	};
	
	private static int N, M;
	private static int[][] office;
	
	private static int answer = 100;
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		
		office = new int[N][M];
		
//		for(int i=0; i<N; i++) {
//			office[i] = Arrays.stream(br.readLine()
//							  .split(" "))
//							  .mapToInt(Integer::parseInt)
//							  .toArray();
//		}
		
		for(int i=0; i<N; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j=0; j<M; j++) {
				// -1:감시 구역, 0:빈칸, 1~5:CCTV, 6:벽
				office[i][j] = Integer.parseInt(st.nextToken());
				
				// CCTV 라면,
				if(1 <= office[i][j] && office[i][j] <= 5) {
					int num = office[i][j];
					// CCTV 위치와 번호 저장
					cctvList.add(new Position(i, j, num));
				}
			}
		}
		
		dfs(0, office);
		System.out.println(answer);
	}
	
	/**
	 * dfs로 CCTV의 감시상태를 업데이트하는 함수
	 * @param cctvCount 현재 dfs 단계에서의 CCTV 개수
	 * @param office 현재 office의 감시 상태
	 */
	private static void dfs(int cctvCount, int[][] office) {
		// 모든 CCTV 체크를 다했다면,
		if(cctvCount == cctvList.size()) {
			// 사각지대의 최소값 업데이트
			answer = Math.min(answer, getBlindSpotCount(office));
			return;
		}
		
		int row = cctvList.get(cctvCount).row; // 행
		int col = cctvList.get(cctvCount).col; // 열
		int num = cctvList.get(cctvCount).num; // CCTV의 번호
		
		// 90도씩 4번 모두 체크 (0, 90, 180, 270)
		for(int d=0; d<4; d++) {
			int[][] copiedOffice = getDeepCopiedOffice(office);
			
			// num번 CCTV의 감시방향
			// 위쪽:0, 오른쪽:1, 아래쪽:2, 왼쪽:3
			for(int move : dir[num]) {
				int nd = (move + d) % 4; // 4번째(360도)는 0번째(0도)와 같기 때문에 %4로 0을 만들어줌
				int nr = row;
				int nc = col;
				
				while(true) {
					nr += dr[nd]; // 회전했을 때의 방향에 따른 row값 한칸씩 이동
					nc += dc[nd]; // 회전했을 때의 방향에 따른 col값 한칸씩 이동
					
					// 이동한 곳이 접근할 수 없거나 벽인 경우
					if(isValidIndex(nr, nc) == false) {
						break;
					}
					
					// 감시 가능한 곳은 -1로 체크
					copiedOffice[nr][nc] = -1;
				}
			}
			
			// 한 개의 CCTV 감시 구역 체크 완료했으므로 cctvCount + 1,
			// 현재 단계에서 감시 체크가 된 깊은 복사한 사무실을 인자로 넘겨줌
			dfs(cctvCount + 1, copiedOffice);
		}
	}
	
	/**
	 * 사각지대의 칸 수를 얻는 함수
	 * @param copiedOffice 복사된 사무실 상태
	 * @return blindSpotCount : Integer
	 */
	private static int getBlindSpotCount(int[][] copiedOffice) {
		int blindSpotCount = 0;
		
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				if(copiedOffice[i][j] == 0) {
					blindSpotCount++;
				}
			}
		}
		
		return blindSpotCount;
	}
	
	/**
	 * 사무실 상태를 깊은 복사해서 반환하는 함수
	 * @param office 사무실 상태
	 * @return deepCopiedOffice : int[][]
	 */
	private static int[][] getDeepCopiedOffice(int[][] office) {
		int[][] deepCopiedOffice = new int[N][M];
		
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				deepCopiedOffice[i][j] = office[i][j];
			}
		}
		
		return deepCopiedOffice;
	}
	
	/**
	 * 행과 열을 인자로 받아, 접근할 수 있는 유효한 인덱스인지 판단해서 boolean 값을 반환하는 함수
	 * @param row 행
	 * @param col 열
	 * @return isValid : Boolean
	 */
	private static boolean isValidIndex(int row, int col) {
		if(row < 0 || row >= N) {
			return false;
		}
		if(col < 0 || col >= M) {
			return false;
		}
		// 벽
		if(office[row][col] == 6) {
			return false;
		}
		
		return true;
	}
}

/**
 * CCTV의 행, 열, 번호를 저장하는 클래스
 */
class Position {
	int row;
	int col;
	int num;
	
	public Position(int row, int col, int num) {
		this.row = row;
		this.col = col;
		this.num = num;
	}
}
저작자표시 (새창열림)

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

백준 / 그래프 / 17471번 / 게리맨더링 / Java  (1) 2023.09.02
백준 / 그래프 / 20058번 / 마법사 상어와 파이어스톰 / Java  (0) 2023.08.27
백준 / 그래프 / 2178번 / 미로 탐색 / JS  (0) 2023.04.28
백준 / 그래프 / 7569번 / 토마토 / JS  (1) 2023.04.28
    'PS/백준' 카테고리의 다른 글
    • 백준 / 그래프 / 17471번 / 게리맨더링 / Java
    • 백준 / 그래프 / 20058번 / 마법사 상어와 파이어스톰 / Java
    • 백준 / 그래프 / 2178번 / 미로 탐색 / JS
    • 백준 / 그래프 / 7569번 / 토마토 / JS
    KimMinJun
    KimMinJun

    티스토리툴바