캐슬 디펜스


백준 17135: 캐슬 디펜스

문제보기
Alt text

풀이

재귀함수를 사용하여 궁수 3명이 배치 될 열을 조합하기

  • combi(int[] tmp, int[] sel, int c, int idx)
  • tmp : 궁수가 배치 될 수 있는 모든 열이 들어 있는 배열
  • sel : 3명의 궁수가 배치 될 3개의 열의 조합 배열
  • c : 조합으로 선택되는 열의 위치를 담을 배열(sel)의 인덱스 번호
  • idx : 열의 위치가 들어있는 배열(tmp)의 인덱스 번호

소스코드

package 백준;

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
	static class Enemy {
		int r, c;

		Enemy(int r, int c) {
			this.r = r;
			this.c = c;
		}

		@Override
		public String toString() {
			return "Enemy [r=" + r + ", c=" + c + "]";
		}
	}

	static ArrayList<Enemy> EnemyList = new ArrayList<>();
	static int N;
	static int M;
	static int D;
	static int[][] map;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt(); // 행의 수
		M = sc.nextInt(); // 열의 수
		D = sc.nextInt(); // 공격 거리 제한
		map = new int[N][M];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				map[i][j] = sc.nextInt();
				if (map[i][j] == 1)
					EnemyList.add(new Enemy(i, j));
			}
		}
		// 궁수가 배치 될 열을 조합으로 찾기
		int[] tmp = new int[M];
		for (int i = 0; i < M; i++) {
			tmp[i] = i;
		}

		combi(tmp, new int[3], 0, 0);
		System.out.println(max);
	}

	static int max = 0;

	static void combi(int[] tmp, int[] sel, int c, int idx) {
		if (c == sel.length) {
			// 공격거리 D만큼 적을 죽여

			ArrayList<Enemy> copyEnemy = new ArrayList<>();
			for (int i = 0; i < EnemyList.size(); i++) {
				copyEnemy.add(new Enemy(EnemyList.get(i).r, EnemyList.get(i).c));
			}

			boolean flag = true;
			int cnt = 0;

			while(flag) {
				ArrayList<Enemy> die = new ArrayList<>();
				for (int i = 0; i < sel.length; i++) {
					int minC = M;
					int minR = 0;
					int dis = 0;
					int min = D;
					for (int k = 0; k < copyEnemy.size(); k++) {
						dis = Math.abs(copyEnemy.get(k).r - N) + Math.abs(copyEnemy.get(k).c - sel[i]);

						if (dis < min) {
							min = dis;
							minR = copyEnemy.get(k).r;
							minC = copyEnemy.get(k).c;
						}

						if (dis == min) {
							if (minC > copyEnemy.get(k).c) {
								minR = copyEnemy.get(k).r;
								minC = copyEnemy.get(k).c;
							}
						}
					}
					if (minC < M)
						die.add(new Enemy(minR, minC)); // 죽을 애들을 리스트에 담아
				}

				// 죽인 적의 수를 먼저 세자
				int tmpR = -1;
				int tmpC = -1;
				for (int i = 0; i < die.size(); i++) {
					if (tmpR != die.get(i).r || tmpC != die.get(i).c) {
						cnt++;
					}
					tmpR = die.get(i).r;
					tmpC = die.get(i).c;
				}

				// 적을 죽이고(적리스트에서 죽을애들리스트에 있는 거 찾아서 지우기)
				int tmpsize = copyEnemy.size();
				for(int i=0; i<die.size(); i++) {
					for(int j=tmpsize-1; j>=0; j--) {
						if(copyEnemy.get(j).r == die.get(i).r && copyEnemy.get(j).c == die.get(i).c) {
							copyEnemy.remove(j);
						}
					}
					tmpsize = copyEnemy.size();
				}

				// 적을 한칸씩 내리기
				int size = copyEnemy.size();
				for (int i = 0; i < size; i++) {
					if (copyEnemy.get(i).r + 1 < N) {
						copyEnemy.add(new Enemy(copyEnemy.get(i).r + 1, copyEnemy.get(i).c));
					}
				}

				for (int i = 0; i < size; i++) {
					copyEnemy.remove(0);
				}

				if (copyEnemy.size() == 0)
					flag = false;
			}

			max = Math.max(max, cnt);
			
			return;
		}

		if (idx == tmp.length)
			return;

		sel[c] = tmp[idx];
		combi(tmp, sel, c + 1, idx + 1);
		combi(tmp, sel, c, idx + 1);
	}
}