Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- dp
- 완전 탐색
- 스프링 시큐리티
- 메모이제이션
- spring cloud
- 게이트웨이
- 백트래킹
- 이분 탐색
- 구간 트리
- 다익스트라
- Logback
- BFS
- spring boot
- Gradle
- docker-compose
- 주울
- 유레카
- 플로이드 와샬
- Zuul
- 도커
- 달팽이
- 서비스 디스커버리
- 구현
- 이분 매칭
- 스택
- Spring Cloud Config
- 비트마스킹
- Java
- 트리
- ZuulFilter
Archives
- Today
- Total
Hello, Freakin world!
[백준 15683번][Java] 감시 - 극한의 구현, 완전 탐색 본문
완전 탐색, DFS를 이용하면 풀 수 있는 문제다. 문제 자체의 알고리즘 난이도는 높지 않다. 하지만 한참 고민했던 문제다.
문제에서 cctv는 5가지 타입이 존재하고 타입별로 가능한 탐색 방향이 존재한다. 이를 단순하게 구현하려면 배열에 5가지 타입별로 각자 방향을 일일이 저장해두고 그대로 이용할 수도 있겠지만... 지저분해지는 코드가 눈에 선했기 때문에
이를 어떻게 구현할지 꽤 오랜 시간동안 생각했다.
(그래도 막상 이 문제를 테스트에서 만난다면 노가다로 풀 것 같다)
해결 방법은 CCTV 객체에 Type이라는 멤버 변수를 추가하고 Type 클래스에 각 타입에 다른 Direction 열거형 클래스를 이용했다.
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/*
백준 15683번 감시
https://www.acmicpc.net/problem/15683
*/
public class Main {
static int R,C;
//dr, dc는 반시계 방향 순으로 나열되어 있음. 0 : 위쪽
static Point[] dPoint = {
Point.create(-1,0),
Point.create(0,-1),
Point.create(1,0),
Point.create(0,1)
};
public static void main(String[] args) throws IOException {
InputReader reader = new InputReader();
// InputReader reader = new InputReader("testcase.txt");
StringTokenizer st = new StringTokenizer(reader.readLine());
R = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
int[][] room = new int[R][C];
List<CCTV> cctvs = new ArrayList<>();
for (int i = 0; i < R; i++) {
st = new StringTokenizer(reader.readLine());
for (int j = 0; j < C; j++) {
room[i][j] = Integer.parseInt(st.nextToken());
if(room[i][j] > 0 && room[i][j] < 6) cctvs.add(new CCTV(Point.create(i,j), new Type(room[i][j])));
}
}
int ret = findMinimumInvisibleArea(0, cctvs, room);
System.out.println(ret);
}
private static int findMinimumInvisibleArea(int index, List<CCTV> cctvs, int[][] room) {
if(index == cctvs.size()) {
return countInvisibleArea(room);
}
//room 복사
int[][] copiedRoom = new int[room.length][room[0].length];
copy(room, copiedRoom);
CCTV cctv = cctvs.get(index);
Point cctvPos = cctv.point;
Direction direction = cctv.type.direction;
int ret = Integer.MAX_VALUE;
for (int i = 0; i < direction.cycleNum; i++) {
for (int j = 0; j < direction.directionPoints.length; j++) {
Point dP = dPoint[direction.directionPoints[j]];
scan(cctvPos.row, cctvPos.col, dP.row, dP.col, room);
}
direction.rotate();
ret = Math.min(findMinimumInvisibleArea(index+1, cctvs, room), ret);
//room 복원
copy(copiedRoom, room);
}
return ret;
}
private static void copy(int[][] ori, int[][] target) {
for (int i = 0; i < ori.length; i++) {
for (int j = 0; j < ori[i].length; j++) {
target[i][j] = ori[i][j];
}
}
}
private static int countInvisibleArea(int[][] room) {
int cnt = 0;
for (int i = 0; i < room.length; i++) {
for (int j = 0; j < room[i].length; j++) {
if(room[i][j] == 0) cnt++;
}
}
return cnt;
}
private static void scan(int row, int col,
int dr, int dc, int[][] room) {
while(true) {
int nextRow = row+dr; int nextCol = col+dc;
if(!isRange(nextRow, nextCol) || room[nextRow][nextCol] == 6) break;
room[nextRow][nextCol] = -1;
row = nextRow; col = nextCol;
}
}
private static boolean isRange(int r, int c) {
if(r < 0 || r >= R || c < 0 || c >= C) return false;
return true;
}
}
class CCTV {
Type type;
Point point;
public CCTV(Point point, Type type) {
this.point = point;
this.type = type;
}
}
class Point {
int row, col;
private Point(int row, int col) {
this.row = row;
this.col = col;
}
public static Point create(int row, int col) {
return new Point(row, col);
}
}
class Type {
int typeId;
Direction direction;
public Type(int typeId) {
this.typeId = typeId;
this.direction = Direction.byType(typeId);
}
}
enum Direction {
TYPE1(1), TYPE2(2),TYPE3(3), TYPE4(4), TYPE5(5);
int type, cycleNum;
int[] directionPoints;
private int[][] firstDirByType = {
{0},
{1, 3},
{0, 1},
{0, 1, 2},
{0, 1, 2, 3}
};
private int[] dirSizeArr = {4,2,4,4,1};
Direction(int type) {
this.type = type;
this.directionPoints = firstDirByType[type-1];
this.cycleNum = dirSizeArr[type-1];
}
public void rotate() {
for (int i = 0; i < directionPoints.length; i++) {
directionPoints[i] = (directionPoints[i]+1)%4;
}
}
public static Direction byType(int type) {
if(type == 1) return Direction.TYPE1;
if(type == 2) return Direction.TYPE2;
if(type == 3) return Direction.TYPE3;
if(type == 4) return Direction.TYPE4;
if(type == 5) return Direction.TYPE5;
throw new IllegalArgumentException("잘못된 타입입니다.");
}
}
class InputReader {
private BufferedReader br;
public InputReader() {
br = new BufferedReader(new InputStreamReader(System.in));
}
public InputReader(String filepath) {
try {
br = new BufferedReader(new FileReader(filepath));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public List<Character> readLineIntoCharList() throws IOException {
List<Character> l = new ArrayList<>();
while(true) {
int readVal = br.read();
if(readVal == '\n' || readVal == -1) break;
l.add((char)readVal);
}
return l;
}
public boolean ready() throws IOException {
return br.ready();
}
public String readLine() throws IOException {
return br.readLine();
}
public int readInt() throws IOException {
return Integer.parseInt(readLine());
}
public Long readLong() throws IOException {
return Long.parseLong(readLine());
}
}
'알고리즘 > PS' 카테고리의 다른 글
[백준 14890번][Java] 경사로 - 구현, 쉬운 듯 어려운 너 (0) | 2020.10.26 |
---|---|
[백준 1918번][Java] 후위 표기식 - 스택, 후위 표기식 변환 알고리즘 (0) | 2020.10.25 |
[백준 17070번][Java] 파이프 옮기기 1 - DP, 메모이제이션 (0) | 2020.10.23 |
[백준 2110번][Java] 공유기 설치 - 이분 탐색/중복된 요소 처리 (0) | 2020.10.21 |
[백준 2522번][Java] 사회망 서비스 - 트리, DP, 메모이제이션 (0) | 2020.10.18 |
Comments