/ BOJ

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;
			}

		}
	}

}

게임 형식을 빌려온 시뮬레이션 문제라서 즐겁게 풀 수 있었던 것 같다.