문제해결/백준
백준 15683번-감시(JAVA)
mangzz
2021. 8. 20. 16:57
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.List;
import java.util.StringTokenizer;
public class observation {
static int N, M;
static int[][] map;
static int[][] deltas = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } };
static List<int[]> cctv = new ArrayList<int[]>();
static int Min = Integer.MAX_VALUE;
static int blind = 0;;
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());
// CCTV이면 cctv 리스트에 종류, 좌표 저장
if (map[i][j] > 0 && map[i][j] < 6) {
int[] e = new int[3];
e[0] = map[i][j];
e[1] = i;
e[2] = j;
cctv.add(e);
}
// map[i][j] == 0이면 감시전 영역 수++
else if (map[i][j] == 0)
blind++;
}
}
permutation(0, new int[cctv.size()]);
if (Min <= 0) {
System.out.println(0);
return;
}
System.out.println(Min);
}
// 중복 순열 뽑는 함수
// cctv리스트에 들어있는 cctv들의 방향 중복 순열 뽑기
private static void permutation(int toSelect, int[] selected) {
if (toSelect == cctv.size()) {
// 중복 순열을 뽑았으면 사각지대 수 계산 함수 호출
calc(selected);
return;
}
for (int i = 0; i < 4; i++) {
selected[toSelect] = i;
permutation(toSelect + 1, selected);
}
}
// 사각지대 수 계산 함수
private static void calc(int[] selected) {
// 매개변수로 넘어온 방향 순열로 계산할 사각지대 수 temp를 blind로 초기화
int temp = blind;
// map 복제
int[][] clone = new int[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
clone[i][j] = map[i][j];
}
}
// cctv의 List에 들어있는 순서대로
for (int i = 0; i < cctv.size(); i++) {
temp = observe(temp, cctv.get(i), selected[i], clone);
}
// 최소 사각지대 갱신
if (Min > temp)
Min = temp;
}
// cctv 감시 수행
private static int observe(int temp, int[] cctv, int selected, int[][] cmap) {
// cctv의 종류에 따라 수행
switch (cctv[0]) {
// 1방향
case 1:
int dx1 = cctv[1] + deltas[selected][0];
int dy1 = cctv[2] + deltas[selected][1];
while (dx1 >= 0 && dy1 >= 0 && dx1 < N && dy1 < M) {
if (cmap[dx1][dy1] == 6)
break;
if (cmap[dx1][dy1] == 0) {
temp--;
cmap[dx1][dy1] = -1;
}
dx1 += deltas[selected][0];
dy1 += deltas[selected][1];
}
break;
// 반대 2방향
case 2:
int dx2 = cctv[1] + deltas[selected][0];
int dy2 = cctv[2] + deltas[selected][1];
while (dx2 >= 0 && dy2 >= 0 && dx2 < N && dy2 < M) {
if (cmap[dx2][dy2] == 6)
break;
if (cmap[dx2][dy2] == 0) {
temp--;
cmap[dx2][dy2] = -1;
}
dx2 += deltas[selected][0];
dy2 += deltas[selected][1];
}
// -deltas[selected];가 반대 방향
dx2 = cctv[1] - deltas[selected][0];
dy2 = cctv[2] - deltas[selected][1];
while (dx2 >= 0 && dy2 >= 0 && dx2 < N && dy2 < M) {
if (cmap[dx2][dy2] == 6)
break;
if (cmap[dx2][dy2] == 0) {
temp--;
cmap[dx2][dy2] = -1;
}
dx2 -= deltas[selected][0];
dy2 -= deltas[selected][1];
}
break;
// 직각방향
case 3:
int dx3 = cctv[1] + deltas[selected][0];
int dy3 = cctv[2] + deltas[selected][1];
while (dx3 >= 0 && dy3 >= 0 && dx3 < N && dy3 < M) {
if (cmap[dx3][dy3] == 6)
break;
if (cmap[dx3][dy3] == 0) {
temp--;
cmap[dx3][dy3] = -1;
}
dx3 += deltas[selected][0];
dy3 += deltas[selected][1];
}
//selected가 deltas의 마지막인 경우 다음 방향은 0
if (selected == 3)
selected = 0;
//selected가 deltas의 마지막이 나닌 경우 다음 방향은 selected += 1
else
selected += 1;
dx3 = cctv[1] + deltas[selected][0];
dy3 = cctv[2] + deltas[selected][1];
while (dx3 >= 0 && dy3 >= 0 && dx3 < N && dy3 < M) {
if (cmap[dx3][dy3] == 6)
break;
if (cmap[dx3][dy3] == 0) {
temp--;
cmap[dx3][dy3] = -1;
}
dx3 += deltas[selected][0];
dy3 += deltas[selected][1];
}
break;
// 3방향
case 4:
for (int i = 0; i < 4; i++) {
// 선택된 방향만 제외하고 3방향 탐색
if (i == selected)
continue;
int dx4 = cctv[1] + deltas[i][0];
int dy4 = cctv[2] + deltas[i][1];
while (dx4 >= 0 && dy4 >= 0 && dx4 < N && dy4 < M) {
if (cmap[dx4][dy4] == 6)
break;
if (cmap[dx4][dy4] == 0) {
temp--;
cmap[dx4][dy4] = -1;
}
dx4 += deltas[i][0];
dy4 += deltas[i][1];
}
}
break;
case 5: // 4방향
for (int i = 0; i < 4; i++) {
int dx5 = cctv[1] + deltas[i][0];
int dy5 = cctv[2] + deltas[i][1];
while (dx5 >= 0 && dy5 >= 0 && dx5 < N && dy5 < M) {
if (cmap[dx5][dy5] == 6)
break;
if (cmap[dx5][dy5] == 0) {
temp--;
cmap[dx5][dy5] = -1;
}
dx5 += deltas[i][0];
dy5 += deltas[i][1];
}
}
break;
}
return temp;
}
}