최's 먹공로그
BOJ15683_감시 본문
https://www.acmicpc.net/problem/15683
문제정리
1. cctv의 종류는 5가지 1: 오른쪽 감시 , 2 : 오른쪽 왼쪽 감시 , 3 : 위 오른쪽 감시 , 4 : 위 오른쪽 왼쪽 감시 , 5 : 위 아래 오른쪽 왼쪽 감시
2. cctv는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다 , 벽은 통과할 수 없고 벽은 6이다
3. cctv는 회전시킬 수 있는데 , 회전은 항상 90도 방향으로 해야 하며 , 감시하려고 하는 방향이 가로 또는 세로 방향 이어야 한다
4. cctv는 다른 cctv를 통과할 수 있다
5. 사무실의 크기와 상태 , cctv정보가 주어졌을 때 , cctv의 방향을 적절히 정해서 사각 지대의 최소크기를 구하는 프로그램을 작성
6. cctv의 최대 개수는 8개를 넘지 않는다
문제issue
cctv 돌리는 부분
1. map에서 cctv 개수를 파악해서 배열을 생성한다
2. 배열에 cctv의 위치와 cctv의 번호를 저장한다
3. [0,1,2,3] 인 배열로 cctv 개수만큼 중복순열 돌려서 돌리는 모든 경우를 다 본다
4. 0은 안돌림 , 1은 한번 돌림 , 2는 2번 돌림 , 3은 3번 돌림
5. 돌린 후 현재 cctv 위치를 기준으로 map_clone에서 어느 방향만 감시할지 보고 감시하는 방향으로만 이동하면서 0이면 8로 마킹해준다
6. 범위를 넘어가거나 벽을 만나면 반복을 종료한다
해결흐름
1. 중복순열을 이용해서 몇 번째 cctv를 각각 몇번 돌릴지 결정
2. cctv의 상태에 맞게 map에서 0인 곳을 임의의 숫자 8로 바꿔준다
3. 모든 cctv를 돌고 빈곳 0을 카운트 해준다
4. 최솟값을 도출한다
소스코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Arrays; import java.util.StringTokenizer; public class Main { static class cctv { int r; int c; int number; public cctv(int r, int c, int number) { super(); this.r = r; this.c = c; this.number = number; } } private static int[] pi_arr = { 0, 1, 2, 3 }; private static int N; private static int M; private static int cctv_cnt; private static int[] temp_arr; private static cctv[] cctv_arr; private static int[][] map; private static int[][] map_clone; private static int min; private static int empty_cnt; public static void main(String[] args) throws Exception { // input BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine().trim(), " "); N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); map = new int[N][M]; map_clone = new int[N][M]; cctv_cnt = 0; for (int i = 0; i < N; i++) { st = new StringTokenizer(br.readLine().trim(), " "); for (int j = 0; j < M; j++) { int number = Integer.parseInt(st.nextToken()); map[i][j] = number; map_clone[i][j] = number; if (number != 0 && number != 6) { cctv_cnt++; } } } // cctv 개수만큼 배열 생성 cctv_arr = new cctv[cctv_cnt]; int cctv_idx = 0; for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { if (map[i][j] != 0 && map[i][j] != 6) { cctv_arr[cctv_idx++] = new cctv(i, j, map[i][j]); } } } // start temp_arr = new int[cctv_cnt]; min = Integer.MAX_VALUE; pi(0); System.out.println(min); } // end of main private static void pi(int len) { if (len == cctv_cnt) { map_clone = new int[N][M]; for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { map_clone[i][j] = map[i][j]; } } empty_cnt = 0; solve(); if (min > empty_cnt) min = empty_cnt; return; } for (int i = 0; i < 4; i++) { temp_arr[len] = pi_arr[i]; pi(len + 1); } } private static void solve() { // temp_arr에 있는 각각의 cctv를 몇번 돌릴지 나와 있는 그대로 돌려보면서 빈곳 0 을 카운트 for (int i = 0; i < cctv_cnt; i++) { // cctv number로 먼저 구분 if (cctv_arr[i].number == 1) { // 몇 번 돌리는 지로 구분 if (temp_arr[i] == 0) { // 현재 cctv위치를 기준으로 map_clone에서 오른쪽만 감시 right(i); } else if (temp_arr[i] == 1) { // 아래만 감시 down(i); } else if (temp_arr[i] == 2) { // 왼쪽만 감시 left(i); } else if (temp_arr[i] == 3) { // 위만 감시 up(i); } } else if (cctv_arr[i].number == 2) { if (temp_arr[i] == 0 || temp_arr[i] == 2) { // 오른쪽 , 왼쪽 감시 right(i); left(i); } else if (temp_arr[i] == 1 || temp_arr[i] == 3) { // 위 , 아래 감시 up(i); down(i); } } else if (cctv_arr[i].number == 3) { if (temp_arr[i] == 0) { // 위 , 오른쪽 감시 up(i); right(i); } else if (temp_arr[i] == 1) { // 아래 , 오른쪽 감시 down(i); right(i); } else if (temp_arr[i] == 2) { // 아래 , 왼쪽 감시 down(i); left(i); } else if (temp_arr[i] == 3) { // 위 , 왼쪽 감시 up(i); left(i); } } else if (cctv_arr[i].number == 4) { if (temp_arr[i] == 0) { // 위 , 오른쪽 , 왼쪽 감시 up(i); right(i); left(i); } else if (temp_arr[i] == 1) { // 위 , 아래 , 오른쪽 감시 up(i); down(i); right(i); } else if (temp_arr[i] == 2) { // 아래 , 오른쪽 , 왼쪽 감시 down(i); right(i); left(i); } else if (temp_arr[i] == 3) { // 아래 , 왼쪽 , 위 감시 down(i); left(i); up(i); } } else if (cctv_arr[i].number == 5) { // 모든경우 사방 감시 up(i); right(i); down(i); left(i); } } // 빈곳 카운트 for (int j = 0; j < N; j++) { for (int k = 0; k < M; k++) { if (map_clone[j][k] == 0) { empty_cnt++; } } } } // end of solve private static void down(int i) { int cctv_r = cctv_arr[i].r; int cctv_c = cctv_arr[i].c; while (true) { cctv_r++; // 범위 넘거가거나 , 벽을 만나면 종료 if (cctv_r >= N || map_clone[cctv_r][cctv_c] == 6) break; // 빈곳은 임의의 숫자 8로 마킹 else if (map_clone[cctv_r][cctv_c] == 0) map_clone[cctv_r][cctv_c] = 8; } } private static void left(int i) { int cctv_r = cctv_arr[i].r; int cctv_c = cctv_arr[i].c; while (true) { cctv_c--; if (cctv_c < 0 || map_clone[cctv_r][cctv_c] == 6) break; else if (map_clone[cctv_r][cctv_c] == 0) map_clone[cctv_r][cctv_c] = 8; } } private static void right(int i) { int cctv_r = cctv_arr[i].r; int cctv_c = cctv_arr[i].c; while (true) { cctv_c++; if (cctv_c >= M || map_clone[cctv_r][cctv_c] == 6) break; else if (map_clone[cctv_r][cctv_c] == 0) map_clone[cctv_r][cctv_c] = 8; } } private static void up(int i) { int cctv_r = cctv_arr[i].r; int cctv_c = cctv_arr[i].c; while (true) { cctv_r--; if (cctv_r < 0 || map_clone[cctv_r][cctv_c] == 6) break; else if (map_clone[cctv_r][cctv_c] == 0) map_clone[cctv_r][cctv_c] = 8; } } } // end of class | cs |
1. 입력시 빈곳의 개수 카운트하고
2. map_clone 맵핑하면서 따로 카운트해준뒤
3. map_clone에서 0인 곳 개수를 다시 카운트 할 필요없이 1 - 2 해주면 됨
이러면 의미있는지는 모르겠지만 150ms 단축
'APS' 카테고리의 다른 글
BOJ14888_연산자끼워넣기 (2) | 2019.07.10 |
---|---|
BOJ14889_스타트와 링크 (0) | 2019.07.06 |
BOJ14500_테트로미노 (2) | 2019.06.26 |
BOJ3190_뱀 (1) | 2019.06.26 |
BOJ14890_경사로 (4) | 2019.06.19 |