danbibibi
article thumbnail

문제

문제 바로가기> BOJ 15683번: 감시

 

15683번: 감시

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

www.acmicpc.net

 

풀이

cctv의 개수가 최대 8개로 적은 편이다.

따라서 가능한 cctv 방향을 모두 시뮬레이션 해보면서, 브루트포스 방식으로 문제를 풀었다.

탐색 방향을 미리 `dir` 배열에 정해두고, 모든 cctv의 방향을 정했을 때, 시뮬레이션 해주면 된다.

 

C++

#include<iostream>
#include<vector>
#define EMPTY 0
#define WALL 6
#define MAX 10
using namespace std;

struct CCTV{int y, x, num;};
vector<CCTV> cctv;

int N, M, ans = MAX*MAX;
int dy[] = {0, 1, 0, -1};  // → ↓ ← ↑
int dx[] = {1, 0, -1, 0};
int dir[MAX], map[MAX][MAX], copy_map[MAX][MAX];

void input(){
    cin >> N >> M;
    for(int i=0; i<N; i++){
        for(int j=0; j<M; j++){
            cin >> map[i][j];
            if(0<map[i][j] && map[i][j]<6) cctv.push_back({i, j, map[i][j]}); // cctv 위치, 종류 저장
        }
    }
}

void check_area(int y, int x, int d){
    int ny=y, nx=x;
    while(1){
        if(ny<0 || ny>=N || nx<0 || nx>=M || map[ny][nx]==WALL) return; // 범위를 벗어나는 경우, 벽인 경우
        copy_map[ny][nx] = map[y][x]; // 감시 영역 check
        ny+=dy[d]; nx+=dx[d]; // move
    }
}

int get_blind_spot(){
    
    // copy 
    for(int i=0; i<N; i++){
        for(int j=0; j<M; j++) copy_map[i][j] = map[i][j];
    }

    // check surveillance area
    for(int i=0; i<cctv.size(); i++){ // cctv 종류에 따라 감시 영역 체크
        int num = cctv[i].num;
        int y = cctv[i].y, x = cctv[i].x;
        if(num == 1) check_area(y, x, dir[i]);
        else if(num == 2){
            check_area(y, x, dir[i]);
            check_area(y, x, (dir[i]+2)%4);
        }
        else if(num == 3){
            check_area(y, x, dir[i]);
            check_area(y, x, (dir[i]+1)%4);
        }
        else if(num == 4){
            check_area(y, x, dir[i]);
            check_area(y, x, (dir[i]+1)%4);
            check_area(y, x, (dir[i]+2)%4);
        }
        else{
            check_area(y, x, dir[i]);
            check_area(y, x, (dir[i]+1)%4);
            check_area(y, x, (dir[i]+2)%4);
            check_area(y, x, (dir[i]+3)%4);
        }
    }

    // check blind spot
    int blind_spot = 0;
    for(int i=0; i<N; i++){
        for(int j=0; j<M; j++){
            if(copy_map[i][j] == EMPTY) blind_spot++;
        }
    } return blind_spot;
}

void solution(int cnt){
    if(cnt == cctv.size()){
        ans = min(ans, get_blind_spot());
        return;
    }
    for(int i=0; i<4; i++){
        dir[cnt] = i; // cctv 방향 설정
        solution(cnt+1);
    }
}

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    input();
    solution(0);
    cout << ans;
}

 

Java

import java.io.*;
import java.util.*;

public class Main{
	
	static final int EMPYT = 0;
	static final int WALL = 6;
	static final int MAX = 8; // CCTV의 최대 개수는 8개를 넘지 않음
	
	static final int dy[] = {0, 1, 0, -1}; // 우 하 좌 상
	static final int dx[] = {1, 0, -1, 0};
	
	
	static int N, M, emptycnt=0;
	static int ans = Integer.MAX_VALUE;	
	static int[][] map;
	static boolean[][] visited;
	static int[] dir;
	static List<int[]> cctv = new ArrayList<>();
	
	public static void main(String[] args) throws Exception {
		// System.setIn(new FileInputStream("res/input.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st =new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		map = new int[N][M];
		dir = new int[MAX];
		
		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(map[i][j]==EMPYT) emptycnt++;
				else if(map[i][j]!=WALL) cctv.add(new int[] {i,j});
			}
		}
		solution(0);
		System.out.println(ans);
	}

	static void solution(int cnt) {
		if(cnt == cctv.size()) {
			ans = Math.min(ans, get_blind_spot());
			return ; 
		}
		for(int d=0; d<4; d++) {
			dir[cnt] = d;
			solution(cnt+1);
		}
	}

	static int get_blind_spot() { // 사각 지대의 크기 반환
		
		int cnt = 0;
		visited = new boolean[N][M];
		
		for(int n=0; n<cctv.size(); n++) {
			int y = cctv.get(n)[0];
			int x = cctv.get(n)[1];
			int d = dir[n];
			
			if(map[y][x] == 1) cnt+=check(y, x, d);
			else if(map[y][x] == 2) {
				cnt+=check(y, x, d);
				cnt+=check(y, x, (d+2)%4);	
			}
			else if(map[y][x] == 3) {
				cnt+=check(y, x, d);
				cnt+=check(y, x, (d+1)%4);
			}
			else if(map[y][x] == 4) {
				cnt+=check(y, x, d);
				cnt+=check(y, x, (d+2)%4);
				cnt+=check(y, x, (d+3)%4);
			}
			else if(map[y][x] == 5) {
				cnt+=check(y, x, d);
				cnt+=check(y, x, (d+1)%4);
				cnt+=check(y, x, (d+2)%4);
				cnt+=check(y, x, (d+3)%4);
			}
		}
		return emptycnt-cnt;
	}

	static int check(int y, int x, int d) {
		
		int ny = y;
		int nx = x;
		int cnt = 0;
		while(true){
			ny+=dy[d]; nx+=dx[d];
			if(ny<0 || ny>=N || nx<0 || nx>=M || map[ny][nx]==WALL) break; // 범위를 벗어나는 경우 벽인 경우 
			if(map[ny][nx] == EMPYT && !visited[ny][nx]) {
				cnt++;
				visited[ny][nx] = true;
			}
		}
		return cnt;
	}
}

'문제 풀이 > SW 역량 테스트' 카테고리의 다른 글

BOJ 16234번: 인구 이동  (1) 2023.01.30
BOJ 15685번: 드래곤 커브  (0) 2023.01.29
BOJ 14501번: 퇴사  (0) 2023.01.24
BOJ 14891번: 톱니바퀴  (0) 2023.01.23
BOJ 14890번: 경사로  (0) 2023.01.22
profile

danbibibi

@danbibibi

꿈을 꾸는 시간은 멈춰 있는 것이 아냐 두려워하지 마 멈추지 마 푸른 꿈속으로