📖 문제
https://www.acmicpc.net/problem/15683
💡 풀이 방식
• 시뮬레이션 + 백트래킹 + 브루트포스
- 각 CCTV의 타입을 받아, 각 타입에 맞춰 회전된 상태를 조합해 사각지대의 최소값을 구한다.
- CCTV 타입이 1( → )인 경우 : 북(0 / ↑), 남(1 / ↓), 서(2 / ←), 동(3 / →)
- CCTV 타입이 2( ↔ )인 경우 : 서동(23 / ↔), 북남(01 / ↕ )
- CCTV 타입이 3(↑→)인 경우 : 북동(03 / ↑→) , 남동(13 / ↓→) , 남서(12 / ↓←) , 북서(02 / ←↑)
- CCTV 타입이 4( ←↑→ )인 경우 : 북서동(023), 북남동(013), 남서동(123), 북남서 (012)
- CCTV 타입이 5(↕↔)인 경우 : 북남서동(0123 / ↕↔ )
static int[][][] mode = {{{0}},
{{0}, {1}, {2}, {3}}, // CCTV 타입이 1인 경우
{{2,3}, {0,1}}, // CCTV 타입이 2인 경우
{{0,3}, {1,3}, {1,2}, {0,2}}, // CCTV 타입이 3인 경우
{{0,2,3}, {0,1,3}, {1,2,3}, {0,1,2}}, // CCTV 타입이 4인 경우
{{0,1,2,3}}}; // CCTV 타입이 5인 경우
- 각 CCTV가 있는 위치와 타입을 CCTV 객체 리스트에 저장한다.
- 그 후, 조합으로 각 cctv마다 특정 경우 조합으로 감시했을 때의 사각지대를 구한 후, 이를 최솟값과 비교하며 사각지대를 최솟값으로 갱신한다.
private static void dfs(int depth, int[][] map) {
// cctv 다 선택해봤을 때 결과 출력
if(depth == list.size()) {
answer = Math.min(answer, check(map));
return;
}
CCTV now = list.get(depth);
int num = now.num;
int r = now.r;
int c = now.c;
for(int i = 0 ; i < mode[num].length ; i++) {
// 배열 복사하기
int[][] copy = new int[N][M];
for(int a = 0 ; a < N ; a++) {
for(int b = 0 ; b < M ; b++)
copy[a][b] = map[a][b];
}
for(int j = 0 ; j < mode[num][i].length ; j++) {
int dir = mode[num][i][j]; // 현재 방향
int nr = r + dr[dir];
int nc = c + dc[dir];
// 격자 범위 벗어나거나, 벽(6)에 닿기 전까지 현재 방향으로 계속 이동
while(true) {
if(nr < 0 || nr >= N || nc < 0 || nc >= M) break;
if(map[nr][nc] == 6) break;
copy[nr][nc] = -1; // 방문 표시
nr += dr[dir];
nc += dc[dir];
}
}
dfs(depth + 1, copy);
}
}
🔺 코드
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
|
import java.util.*;
import java.io.*;
public class Main {
static int[] dr = {-1,1,0,0}; // 북남서동
static int[] dc = {0,0,-1,1};
// 90도로 회전할 수 있는 경우의 수
static int[][][] mode = {{{0}},
{{0}, {1}, {2}, {3}}, // CCTV 타입이 1인 경우
{{2,3}, {0,1}}, // CCTV 타입이 2인 경우
{{0,3}, {1,3}, {1,2}, {0,2}}, // CCTV 타입이 3인 경우
{{0,2,3}, {0,1,3}, {1,2,3}, {0,1,2}}, // CCTV 타입이 4인 경우
{{0,1,2,3}}}; // CCTV 타입이 5인 경우
static int N,M, answer;
static int[][] map;
static int zeroCnt = 0;
static List<CCTV> list = new ArrayList<>(); // CCTV 위치 저장 리스트
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()); // 가로
map = 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());
if(map[i][j] == 0)
zeroCnt++;
else if(map[i][j] >= 1 && map[i][j] <= 5)
list.add(new CCTV(i, j, map[i][j]));
}
}
answer = zeroCnt;
dfs(0, map);
System.out.println(answer);
}
// 각 cctv마다 특정 경우에 조합으로 감시했을 때 사각지대가 얼마인지 구하는 메소드
private static void dfs(int depth, int[][] map) {
// 모든 cctv를 다 확인해봤다면, 사각지대의 최소값 갱신
if(depth == list.size()) {
answer = Math.min(answer, check(map));
return;
}
CCTV now = list.get(depth);
int num = now.num;
int r = now.r;
int c = now.c;
for(int i = 0 ; i < mode[num].length ; i++) {
// 배열 복사하기
int[][] copy = new int[N][M];
for(int a = 0 ; a < N ; a++) {
for(int b = 0 ; b < M ; b++)
copy[a][b] = map[a][b];
}
for(int j = 0 ; j < mode[num][i].length ; j++) {
int dir = mode[num][i][j]; // 현재 방향
int nr = r + dr[dir];
int nc = c + dc[dir];
// 격자 범위 벗어나거나, 벽(6)에 닿기 전까지 현재 방향으로 계속 이동
while(true) {
if(nr < 0 || nr >= N || nc < 0 || nc >= M) break;
if(map[nr][nc] == 6) break;
copy[nr][nc] = -1; // 방문 표시
nr += dr[dir];
nc += dc[dir];
}
}
dfs(depth + 1, copy);
}
}
// 사각지대(0) 구하는 메소드
private static int check(int[][] map) {
int cnt = 0;
for(int i = 0 ; i < N ; i++) {
for(int j = 0 ; j < M ; j++) {
if(map[i][j] == 0)
cnt++;
}
}
return cnt;
}
}
class CCTV {
int r, c, num;
public CCTV(int r, int c, int num) {
this.r = r;
this.c = c;
this.num = num;
}
}
|
cs |
➕ 다른 풀이 방식
- 왼쪽,오른쪽,위,아래 방향을 탐색하는 함수를 별도로 만들어 푸셨다.
[백준]15683: 감시(java)
https://www.acmicpc.net/problem/15683 15683번: 감시 스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는
koguri.tistory.com
- 개인적으로 이게 조금 더 깔끔하고 가독성 좋은 것 같다. ✅
백준 / 백트래킹 / 15683번 / 감시 / Java
< 문제 바로가기 > 15683번: 감시 스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5
jun-coding.tistory.com
- BFS를 활용한 풀이
[백준 - Java] 15683번 : 감시 (삼성 SW 역량 테스트 기출 문제)
문제 www.acmicpc.net/problem/15683 15683번: 감시 스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데
minhamina.tistory.com
💦 어려웠던 점
- 어떻게 일일이 타입마다 회전을 시키지?의 문제
🧐 새로 알게 된 내용
- 함수 파라미터로 값 변경된 배열을 들고 가서 활용하는 것,,, 그럼 원본 배열을 수정하고 복구하고 이런 과정을 하지 않아도 된다...
1회독 | 2회독 | 3회독 | 4회독 | 5회독 |
V |
(참고)
✔ 풀이 참고
BOJ - 감시 15683번 (Java)
❓ 문제 - 백준 감시 15683번 - JAVA 풀이법 출처 (https://www.acmicpc.net/problem/15683) 📝 문제해결법 1. 이 문제는 DFS+구현으로 풀었다. 각 CCTV의 타입을 받아서 각 타입에 맞춰서 회전된 상태를 조합하여
developer-ellen.tistory.com
'코테 > 백준' 카테고리의 다른 글
[백준/JAVA] 3019번: 테트리스 (0) | 2024.04.30 |
---|---|
[백준/JAVA] 16509번: 장군 (0) | 2024.04.30 |
[백준/JAVA] 1967번: 트리의 지름 (0) | 2024.04.30 |
[백준/JAVA] 16937번: 두 스티커 (0) | 2024.04.29 |
[백준/JAVA] 12872번: 플레이리스트 (0) | 2024.04.29 |