BOJ_17135_캐슬디펜스_JAVA
문제 : 캐슬디펜스
링크 : BOJ_17135_캐슬디펜스
접근 방식
디펜스 게임을 구현하는 것 같은 문제였다.
N*M 배열의 값을 읽어오면서, 적의 위치를 모두 리스트에 추가해둔다.
조합으로 M 개중에 3개를 선택하여 궁수를 배치한다.
그 후, 적의 위치를 가져와 각 궁수별로 가장 가까운 적의 위치를 저장해둔다.
모두 저장한 뒤에 일제히 사격처리하여 리스트에서 삭제하여 적을 삭제처리한다. (이렇게 해야 같은 적 개체를 공격할 경우도 체크할 수 있다.)
그 후, 적 개체의 위치를 한 칸씩 성의 위치로 당긴다.
위 로직을 배열 위에 적이 아무도 없을 때까지 반복하면 된다.
소스코드의 주석을 모두 달아놨으니 참고하여 살펴보자.
소스 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class BOJ_17135_캐슬디펜스 {
// input
static int N, M, D, arr[][];
// 조합 목록
static int[] numbers;
// 적 유닛 리스트
static ArrayList<int[]> enemys;
// 잡을 수 있는 유닛 수
static int count, ans;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(in.readLine(), " ");
// 값 가져오기
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
D = Integer.parseInt(st.nextToken());
// 배열 생성
arr = new int[N + 1][M];
numbers = new int[3];
// 배열 값 할당
for (int i = 0; i < N; i++) {
st = new StringTokenizer(in.readLine(), " ");
for (int j = 0; j < M; j++) {
arr[i][j] = Integer.parseInt(st.nextToken());
}
}
comb(0, 0);
System.out.println(ans);
}
// M개중에 3개 고르기 조합(0부터시작)
public static void comb(int cnt, int start) {
if (cnt == 3) {
System.out.println(Arrays.toString(numbers));
// 카운트 초기화
count = 0;
// 게임 시작
attack();
// 최댓값 저장
ans = Math.max(ans, count);
return;
}
for (int i = start; i < M; i++) {
numbers[cnt] = i;
comb(cnt + 1, i + 1);
}
}
public static void attack() {
// 배열 복사
int[][] arrClone = new int[N+1][M];
for(int i=0;i<=N;i++) {
arrClone[i] = arr[i].clone();
}
// 적 유닛 리스트 생성 (배열 탐색하여 1인 경우 리스트에 추가)
enemys = new ArrayList<>();
for(int i=0;i<N;i++) {
for(int j=0;j<M;j++) {
if(arrClone[i][j] == 1) {
enemys.add(new int[] {i,j});
}
}
}
// 무한반복 : 종료조건 - 배열에 1이 더이상 없을 경우
while(true) {
// 각 궁수 좌표 저장할 배열
int mx[] = new int[3];
int my[] = new int[3];
// 각 궁수로부터 적의 최단 거리 저장할 배열
int dist[] = new int[3];
// 궁수의 수만큼 반복
for (int j = 0; j < 3; j++) {
// 궁수의 좌표 설정
int x = N;
int y = numbers[j];
// 궁수로부터 적까지의 거리 초기화
dist[j] = Integer.MAX_VALUE;
// 적 유닛의 수만큼 반복
for (int i = 0, n = enemys.size(); i < n; i++) {
// 적 유닛의 좌표 가져오기
int tempX = enemys.get(i)[0];
int tempY = enemys.get(i)[1];
// 궁수로부터 적 유닛까지의 거리
int temp = Math.abs(x - tempX) + Math.abs(y - tempY);
// 거리 최솟값 구하는 부분
if (dist[j] > temp) {
dist[j] = temp;
mx[j] = tempX;
my[j] = tempY;
// 거리가 같을 경우
} else if (dist[j] == temp) {
// 더 왼쪽에 있는 적으로 좌표 설정
if (my[j] > tempY) {
mx[j] = tempX;
my[j] = tempY;
}
}
}
}
// 궁수가 맞출수 있는 거리면, 카운트를 1 증가시키고 해당 적 유닛 좌표의 값을 0으로
// 여러 궁수가 적 유닛 하나를 공격할 수 있으므로, 해당 좌표의 값이 1인 경우에만 수행
for (int i = 0; i < 3; i++) {
if (arrClone[mx[i]][my[i]] == 1 && dist[i] <= D) {
count++;
arrClone[mx[i]][my[i]] = 0;
}
}
// 적 유닛 좌표 이동 및, 리스트 갱신
enemys = new ArrayList<>();
boolean check = false;
for (int i = N; i >=0; i--) {
for (int j = 0; j < M; j++) {
if(arrClone[i][j] == 1) {
// 성의 위치의 행 좌표는 N, 따라서 i+1이 N일 경우 적 유닛 삭제
if(i+1 != N) {
arrClone[i][j] = 0;
arrClone[i+1][j] = 1;
// 만약 적이 1마리라도 있다면 check 변수가 true;
check = true;
enemys.add(new int[] {i+1,j});
}
}
}
}
// 배열에 적이 없는 경우 반복문 탈출
if(!check) {
break;
}
}
}
}
게임 형식을 빌려온 시뮬레이션 문제라서 즐겁게 풀 수 있었던 것 같다.