알고리즘/백준
15683_감시
베리영young
2024. 8. 20. 22:11
사용 알고리즘: 빡구현, 순조부, dfs
사용 언어: java
cctv를 한꺼번에 처리하는 방법이 없을까? 고민했지만 그런 건 없는 거 같다ㅎㅎ 그리하여 시작된 빡!구현..
사각지대 없애는 건 모듈화해서 재활용하려고 했다(remove~ 이름의 메서드들)
5번 cctv는 방향이 의미가 없으므로 맨처음에 먼저 동작시키고, 나머지 cctv의 방향을 정했다.
package ssafyAlgorithm;
import java.io.*;
import java.util.*;
public class Main_bj_15683_감시 {
static int n,m, map[][];
static ArrayList<int[]>[] cctv = new ArrayList[6];
static int[][] dir;
static int ans = Integer.MAX_VALUE;
public static void main(String[] args) {
input_15683();
//5번 cctv는 먼저 동작 => 사각지대가 아닌 곳은 -1
for(int[] cctv5 : cctv[5]) {
map = cctv5(cctv5, map);
}
//순열(순서 중요)로 cctv방향 정하기
permutation(1, 0); //1번 cctv
System.out.println(ans);
}
private static void permutation(int cctvNum, int cctvOrder) {
if(cctvNum >= 5) {
//cctv작동하기
int[][] copyMap = copy(map);
ans = Math.min(ans, operate(copyMap));
return;
}
if (cctv[cctvNum].size() > cctvOrder) {
for (int d = 0; d < 4; d++) {
dir[cctvNum][cctvOrder] = d;
permutation(cctvNum, cctvOrder + 1); // cctvOrder를 1 증가시켜 다음 방향으로 탐색
}
} else {
permutation(cctvNum + 1, 0); // 다음 CCTV로 이동
}
// if(cctv[cctvNum].size() == cctvOrder) {
// permutation(cctvNum+1, 0);
// }
//
// for(int d=0; d<4; d++) {
// dir[cctvNum][cctvOrder] = d;
// permutation(cctvNum, 1+cctvOrder);
// }
}
private static int operate(int[][] copyMap) {
//1~4번 cctv를 작동한 후,
for(int cctvNum=1; cctvNum<5; cctvNum++) {
for(int cctvOrder=0; cctvOrder<cctv[cctvNum].size(); cctvOrder++) {
copyMap = cctvOper(cctvNum, dir[cctvNum][cctvOrder], cctv[cctvNum].get(cctvOrder), copyMap);
}
}
//사각지대 개수 구하기(map에서 0인 부분)
int zero = 0;
for (int i = 0; i < n; i++) {
for(int j = 0; j<m; j++) {
if(copyMap[i][j] == 0) zero++;
}
}
return zero;
}
private static int[][] cctvOper(int cctvNum, int d, int[] xy, int[][] map) {
if(cctvNum==1) {
if(d==0) {
map = removeRight(xy[0], xy[1], map);
} else if(d==1) {
map = removeDown(xy[0], xy[1], map);
} else if(d==2) {
map = removeLeft(xy[0], xy[1], map);
} else {
map = removeUp(xy[0], xy[1], map);
}
} else if(cctvNum==2) {
if(d%2 == 0) {
map = removeRight(xy[0], xy[1], map);
map = removeLeft(xy[0], xy[1], map);
} else {
map = removeUp(xy[0], xy[1], map);
map = removeDown(xy[0], xy[1], map);
}
} else if(cctvNum==3) {
if(d==0) {
map = removeUp(xy[0], xy[1], map);
map = removeRight(xy[0], xy[1], map);
} else if(d==1) {
map = removeRight(xy[0], xy[1], map);
map = removeDown(xy[0], xy[1], map);
} else if(d==2) {
map = removeDown(xy[0], xy[1], map);
map = removeLeft(xy[0], xy[1], map);
} else {
map = removeLeft(xy[0], xy[1], map);
map = removeUp(xy[0], xy[1], map);
}
} else {
if(d==0) {
map = removeLeft(xy[0], xy[1], map);
map = removeUp(xy[0], xy[1], map);
map = removeRight(xy[0], xy[1], map);
} else if(d==1) {
map = removeUp(xy[0], xy[1], map);
map = removeRight(xy[0], xy[1], map);
map = removeDown(xy[0], xy[1], map);
} else if(d==2) {
map = removeRight(xy[0], xy[1], map);
map = removeDown(xy[0], xy[1], map);
map = removeLeft(xy[0], xy[1], map);
} else {
map = removeDown(xy[0], xy[1], map);
map = removeLeft(xy[0], xy[1], map);
map = removeUp(xy[0], xy[1], map);
}
}
return map;
}
private static int[][] copy(int[][] map2) {
int[][] mmap = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
mmap[i][j] = map2[i][j];
}
}
return mmap;
}
private static int[][] cctv5(int[] cctv5, int[][] map) {
int x = cctv5[0]; int y = cctv5[1];
//위
map = removeUp(x, y, map);
//아래
map = removeDown(x, y, map);
//왼
map = removeLeft(x, y, map);
//오른
map = removeRight(x, y, map);
return map;
}
private static int[][] removeRight(int x, int y, int[][] map) {
for (int j=y+1; j<m; j++) {
if(map[x][j] == 6) break;
map[x][j] = -1;
}
return map;
}
private static int[][] removeLeft(int x, int y, int[][] map) {
for (int j=y-1; j>=0; j--) {
if(map[x][j] == 6) break;
map[x][j] = -1;
}
return map;
}
private static int[][] removeDown(int x, int y, int[][] map) {
for(int i=x+1; i<n; i++) {
if(map[i][y] == 6) break;
map[i][y] = -1;
}
return map;
}
private static int[][] removeUp(int x, int y, int[][] map) {
for(int i=x-1; i>=0; i--) {
if(map[i][y] == 6) break;
map[i][y] = -1;
}
return map;
}
private static void input_15683() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
map = new int[n][m];
dir = new int[5][]; //1~4까지 사용
for (int i = 0; i < 6; i++) {
//cctv는 인덱스 1부터 5까지
//{x위치, y위치, cctv방향}
cctv[i] = new ArrayList<>();
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
map[i][j] = sc.nextInt();
if(map[i][j]>=1 && map[i][j]<=5) {
cctv[map[i][j]].add(new int[] {i,j});
}
}
}
for(int i=1; i<5; i++) {
dir[i] = new int[cctv[i].size()];
} //cctv의 방향 결정
}
}
여기서 문제가 됐던 부분은
private static void permutation(int cctvNum, int cctvOrder) {
if(cctvNum >= 5) {
//cctv작동하기
int[][] copyMap = copy(map);
ans = Math.min(ans, operate(copyMap));
// System.out.println("ans: "+ans);
return;
}
if (cctv[cctvNum].size() > cctvOrder) {
for (int d = 0; d < 4; d++) {
dir[cctvNum][cctvOrder] = d;
permutation(cctvNum, cctvOrder + 1); // cctvOrder를 1 증가시켜 다음 방향으로 탐색
}
} else {
permutation(cctvNum + 1, 0); // 다음 CCTV로 이동
}
// if(cctv[cctvNum].size() == cctvOrder) {
// permutation(cctvNum+1, 0);
// }
//
// for(int d=0; d<4; d++) {
// dir[cctvNum][cctvOrder] = d;
// permutation(cctvNum, 1+cctvOrder);
// }
}
인데,
밑에 주석처리 한 곳처럼 하면, 한 바퀴를 돈 후 ArrayOutOfIndex인가 하는 에러가 생긴다.
그래서 사이즈보다, 현재 order가 작을 때 방향을 정하고, 그 외에는 다음 cctv로 넘어가게 바꾸니까 잘 동작한다.
이거나 저거나 동작 방법은 같은 거 아닌가??? 왜 주석처리 한 부분은 에러가 나는지 모르겠다.
길을 가다가 이 글을 보는 분은 답을 알려주시면 감사하겠습니다ㅎㅎ