티스토리 뷰

728x90

문제

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

 

15683번: 감시

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

www.acmicpc.net

 

풀이 및 소스코드

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

class Main {
	static int n,m;
	static int[] dx = {-1, 1, 0, 0};
	static int[] dy = {0, 0, -1, 1}; //상하좌우
	static int[][][] move = { //move[cctv번호][방향의 경우의 수][세부 방향]
			{{0}},
			{{0},{1},{2},{3}},
			{{0,1},{2,3}},
			{{0,2},{0,3},{1,2},{1,3}},
			{{0,1,2},{0,1,3},{1,2,3},{0,2,3}},
			{{0,1,2,3}}
	};
	static ArrayList<XY> cctv = new ArrayList<>();
	static int cctv_n;
	static int res = Integer.MAX_VALUE;
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		st = new StringTokenizer(br.readLine());
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		int map[][] = new int[n][m]; 
		int empty_area = 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());
				if(1<=map[i][j]&&map[i][j]<=5) {
					cctv.add(new XY(map[i][j], i, j)); //시시티비면 좌표 저장
				}
				else if(map[i][j]==6){ //벽이면
					empty_area--; //빈공간 갯수 하나 줄이기
				}
			}
		}
		cctv_n = cctv.size(); //시시티비의 갯수 저장
		select_direction(0, empty_area-cctv_n, map);
		System.out.println(res);
		
	}
	
	public static void select_direction(int cnt, int empty, int[][] map) {
    //카메라 방향을 정하는 메소드
		if(cnt == cctv_n) {
			
			res = Math.min(res, empty); //사각지대 갯수 비교
			
			return;
		}
		
		int[][] map_copy = new int[n][m]; 
        //map -> 이전 단계까지의 맵
        //map_copy -> 현재 단계에서의 맵. 카메라 방향의 경우의 수에 따라 다른 맵이 되므로 하나의 경우의 수 처리가 끝나면 반드시 초기화(이전단계의 맵) 해준다.
		
		for(int i=0;i<n;i++) { //맵 복사
			for(int j=0;j<m;j++) {
				map_copy[i][j] = map[i][j];
			}
		}
		
		for(int i=0;i<move[cctv.get(cnt).type].length;i++) { 
        //cnt번째 cctv 타입에 따른 모든 방향의 경우의 수를 따져줌
			int count = 0;
			for(int j=0;j<move[cctv.get(cnt).type][i].length;j++) { //방향 하나하나씩 해보기.
				count += make_area(cctv.get(cnt).x, cctv.get(cnt).y, move[cctv.get(cnt).type][i][j], map_copy);
			}
			select_direction(cnt+1, empty-count, map_copy); //다음단계로 진행
			for(int k=0;k<n;k++) { //다음 cctv 방향도 고려해봐야하므로 초기화
				for(int j=0;j<m;j++) {
					map_copy[k][j] = map[k][j];
				}
			}
		}
	}
	
	public static int make_area(int x, int y, int d, int[][] map) {
    //사각지대를 없애는 메소드
		int cnt = 0;
		while(true) {
			x += dx[d];
			y += dy[d];
			if(0>x||0>y||n<=x||m<=y||map[x][y]==6) { //범위에서 벗어나거나 벽을 만나면 cnt 리턴
				return cnt;
			}
			if(map[x][y]==0) {//빈칸인경우
				cnt++;
				map[x][y] = -1;
			}
		}
	}
}

class XY{
	int type;
	int x;
	int y;
	
	public XY(int type,int x, int y) {
		super();
		this.type = type;
		this.x = x;
		this.y = y;
	}
	
}
반응형