스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다.
1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할 수 있다.
CCTV는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다. 사무실에는 벽이 있는데, CCTV는 벽을 통과할 수 없다. CCTV가 감시할 수 없는 영역은 사각지대라고 한다.
CCTV는 회전시킬 수 있는데, 회전은 항상 90도 방향으로 해야 하며, 감시하려고 하는 방향이 가로 또는 세로 방향이어야 한다.
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0
지도에서 0은 빈 칸, 6은 벽, 1~5는 CCTV의 번호이다. 위의 예시에서 1번의 방향에 따라 감시할 수 있는 영역을 '#
'로 나타내면 아래와 같다.
CCTV는 벽을 통과할 수 없기 때문에, 1번이 → 방향을 감시하고 있을 때는 6의 오른쪽에 있는 칸을 감시할 수 없다.
0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5
위의 예시에서 감시할 수 있는 방향을 알아보면 아래와 같다.
CCTV는 CCTV를 통과할 수 있다. 아래 예시를 보자.
0 0 2 0 3
0 6 0 0 0
0 0 6 6 0
0 0 0 0 0
위와 같은 경우에 2의 방향이 ↕ 3의 방향이 ←와 ↓인 경우 감시받는 영역은 다음과 같다.
# # 2 # 3
0 6 # 0 #
0 0 6 6 #
0 0 0 0 #
사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.
첫째 줄에 사무실의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 8)
둘째 줄부터 N개의 줄에는 사무실 각 칸의 정보가 주어진다. 0은 빈 칸, 6은 벽, 1~5는 CCTV를 나타내고, 문제에서 설명한 CCTV의 종류이다.
CCTV의 최대 개수는 8개를 넘지 않는다.
첫째 줄에 사각 지대의 최소 크기를 출력한다.
입력 | 출력 |
---|---|
4 6 | |
0 0 0 0 0 0 | |
0 0 0 0 0 0 | |
0 0 1 0 6 0 | |
0 0 0 0 0 0 | 20 |
6 6 | |
0 0 0 0 0 0 | |
0 2 0 0 0 0 | |
0 0 0 0 6 0 | |
0 6 0 0 2 0 | |
0 0 0 0 0 0 | |
0 0 0 0 0 5 | 15 |
6 6 | |
1 0 0 0 0 0 | |
0 1 0 0 0 0 | |
0 0 1 0 0 0 | |
0 0 0 1 0 0 | |
0 0 0 0 1 0 | |
0 0 0 0 0 1 | 6 |
6 6 | |
1 0 0 0 0 0 | |
0 1 0 0 0 0 | |
0 0 1 5 0 0 | |
0 0 5 1 0 0 | |
0 0 0 0 1 0 | |
0 0 0 0 0 1 | 2 |
1 7 | |
0 1 2 3 4 5 6 | 0 |
3 7 | |
4 0 0 0 0 0 0 | |
0 0 0 2 0 0 0 | |
0 0 0 0 0 0 4 | 0 |
처음에는 카메라가 네 방향으로 회전하면서 감시 가능한 영역을 모두 조사하고, 가장 많이 조사할 수 있는 영역을 조사한 뒤에 사각지대를 찾으려고 했음. 테케랑 반례 다 맞는데 제출만 하면 1퍼에서 끝남.. ㅜ 이유를 모르겠네
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
// https://www.acmicpc.net/problem/15683
public class four15683 {
private int suspected;
private int colNum;
private int rowNum;
private int[][] map;
private int[] dCol = new int[]{-1, 0, 1, 0};
private int[] dRow = new int[]{0, 1, 0, -1};
private int[][] cctvInfo = new int[][]{{0, 1, 0, 0},
{0, 1, 0, 1},
{1, 1, 0, 0},
{1, 1, 0, 1},
{1, 1, 1, 1}};
private boolean[][] watched;
public void solution() throws IOException {
Scanner sc = new Scanner(System.in);
colNum = sc.nextInt();
rowNum = sc.nextInt();
map = new int[colNum][rowNum];
watched = new boolean[colNum][rowNum];
for (int i = 0; i < colNum; i++) {
for (int j = 0; j < rowNum; j++) {
map[i][j] = sc.nextInt();
}
}
suspected = 0;
for (int i = 0; i < colNum; i++) {
for (int j = 0; j < rowNum; j++) {
if (map[i][j] != 0 && map[i][j] != 6) {
watched[i][j] = true;
suspected++;
direction(i, j);
}
if (map[i][j] == 6 && !watched[i][j]) {
watched[i][j] = true;
suspected++;
}
}
}
int count = 0;
for (int i = 0; i < colNum; i++) {
for (int j = 0; j < rowNum; j++) {
if (map[i][j] == 0 && !watched[i][j]) count++;
}
}
System.out.println(count);
}
private void direction(int col, int row) {
int[] cctv = cctvInfo[map[col][row] - 1];
List<int[]>[] findMax = new List[4];
// cctv 네 번 회전
for (int i = 0; i < 4; i++) {
findMax[i] = new ArrayList<>();
// 네 방향 검사
for (int j = 0; j < 4; j++) {
int rawCol = col;
int rawRow = row;
// 해당 방향의 카메라가 아니라면
if (cctv[j] == 0) continue;
else {
while (true) {
int nextCol = rawCol + dCol[j];
int nextRow = rawRow + dRow[j];
if (nextCol < 0 || nextCol >= colNum || nextRow < 0 || nextRow >= rowNum || map[nextCol][nextRow] == 6) {
break;
}
if (!watched[nextCol][nextRow]) {
findMax[i].add(new int[]{nextCol, nextRow});
watched[nextCol][nextRow] = true;
}
rawCol = nextCol;
rawRow = nextRow;
}
}
}
cctv = turnRight(cctv);
}
int max = Integer.MIN_VALUE;
int maxIndex = -1;
for (int i = 0; i < 4; i++) {
if (findMax[i].size() > max) {
max = findMax[i].size();
maxIndex = i;
}
}
for (int i = 0; i < 4; i++) {
if (i == maxIndex) continue;
for (int j = 0; j < findMax[i].size(); j++) {
watched[findMax[i].get(j)[0]][findMax[i].get(j)[1]] = false;
}
}
suspected += max;
}
private int[] turnRight(int[] cctv) {
int temp = cctv[3];
cctv[3] = cctv[2];
cctv[2] = cctv[1];
cctv[1] = cctv[0];
cctv[0] = temp;
return cctv;
}
public static void main(String[] args) throws IOException {
new four15683().solution();
}
}
import java.io.IOException;
import java.util.*;
class CCTV {
int col;
int row;
int num;
CCTV(int col, int row, int num) {
this.col = col;
this.row = row;
this.num = num;
}
}
public class four15683 {
private int colNum;
private int rowNum;
private int[] output;
private int[][] map;
private int[][] copyMap;
private List<CCTV> cctvList = new ArrayList<>();
private int[] dCol = new int[]{-1, 0, 1, 0};
private int[] dRow = new int[]{0, 1, 0, -1};
private int result = Integer.MAX_VALUE;
public void solution() throws IOException {
Scanner sc = new Scanner(System.in);
colNum = sc.nextInt();
rowNum = sc.nextInt();
map = new int[colNum][rowNum];
for (int i = 0; i < colNum; i++) {
for (int j = 0; j < rowNum; j++) {
map[i][j] = sc.nextInt();
if (map[i][j] != 0 && map[i][j] != 6) {
cctvList.add(new CCTV(i, j, map[i][j]));
}
}
}
output = new int[cctvList.size()];
permutaion(0, cctvList.size());
if (result == Integer.MAX_VALUE) result = 0;
System.out.println(result);
}
private void permutaion(int depth, int size) {
if (depth == size) {
copyMap = new int[colNum][rowNum];
for (int i = 0; i < colNum; i++) {
for (int j = 0; j < rowNum; j++) {
copyMap[i][j] = map[i][j];
}
}
for (int i = 0; i < cctvList.size(); i++) {
direction(cctvList.get(i), output[i]);
}
getBlindSpot();
return;
}
for (int i = 0; i < 4; i++) {
output[depth] = i;
permutaion(depth + 1, size);
}
}
private void getBlindSpot() {
int count = 0;
for (int i = 0; i < colNum; i++) {
for (int j = 0; j < rowNum; j++) {
if (copyMap[i][j] == 0) count++;
}
}
result = Math.min(result, count);
}
private void direction(CCTV cctv, int d) {
int cctvNum = cctv.num;
if (cctvNum == 1) {
watch(cctv, d);
} else if (cctvNum == 2) {
watch(cctv, d);
watch(cctv, (d + 2) % 4);
} else if (cctvNum == 3) {
watch(cctv, d);
watch(cctv, (d + 1) % 4);
} else if (cctvNum == 4) {
watch(cctv, d);
watch(cctv, (d + 1) % 4);
watch(cctv, (d + 3) % 4);
} else if (cctvNum == 5) {
watch(cctv, 0);
watch(cctv, 1);
watch(cctv, 2);
watch(cctv, 3);
}
}
private void watch(CCTV cctv, int d) {
Queue<int[]> toVisit = new LinkedList<>();
toVisit.add(new int[]{cctv.col, cctv.row});
while (!toVisit.isEmpty()) {
int[] now = toVisit.poll();
int nextCol = now[0] + dCol[d];
int nextRow = now[1] + dRow[d];
if (nextCol < 0 || nextCol >= colNum
|| nextRow < 0 || nextRow >= rowNum
|| copyMap[nextCol][nextRow] == 6) {
break;
}
toVisit.add(new int[]{nextCol, nextRow});
if (copyMap[nextCol][nextRow] == 0) {
copyMap[nextCol][nextRow] = 7;
}
}
}
public static void main(String[] args) throws IOException {
new four15683().solution();
}
}