🟦/백준
[골드 3] 캐슬 디펜스
진뚱이용
2023. 8. 29. 16:45
https://www.acmicpc.net/problem/17135
17135번: 캐슬 디펜스
첫째 줄에 격자판 행의 수 N, 열의 수 M, 궁수의 공격 거리 제한 D가 주어진다. 둘째 줄부터 N개의 줄에는 격자판의 상태가 주어진다. 0은 빈 칸, 1은 적이 있는 칸이다.
www.acmicpc.net
중간에 개 절었음
1. 0 ~ j-1 중에 3개 조합으로 뽑아 (궁수가 놓일 자리임)
2. 각 조합마다 시뮬레이션을 돌려
2-1. 세로번 돌려
2-1-1. 1 궁수에 1적 찾아
2-1-2. 적 실제로 죽이고 kill++
2-1-3. 배열 밑으로 밀기
3. 시뮬 값 answer와 업데이트
개 절은 곳
while (!queue.isEmpty()) {
Point tmp = queue.remove();
if (Math.abs(arr.length - tmp.y) + Math.abs(j - tmp.x) > D)
break;
if (arr[tmp.y][tmp.x] == 1)
return tmp;
거리 체크 하는 곳을 위에 써야 하는데 return tmp 보다 아래에 써서
거리가 안되는데 찾은 경우도 kill을 해버림
* bfs는 같은 depth를 전부 탐색한 뒤에 depth+1을 탐색하기 때문에 굳이 pQ로 안 만들어도 된다.
* 왼쪽 위 오른쪽 이렇게 queue에 넣으면 같은 depth 기준 왼쪽 위 오른쪽 잘 탐색함
import java.io.*;
import java.util.*;
class Point {
int y, x;
Point(int y, int x) {
this.y = y;
this.x = x;
}
}
public class Main {
public static int answer = Integer.MIN_VALUE;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
StringTokenizer st;
int N, M, D;
int[][] arr;
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
D = Integer.parseInt(st.nextToken());
arr = new int[N][M];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {
arr[i][j] = Integer.parseInt(st.nextToken());
}
}
/////////////////////////////////////////////////////
// 조합으로 n개 중에 3개 뽑아 궁수 배치 해
boolean[] visited = new boolean[arr[0].length];
combination(arr, visited, 0, -1, D);
System.out.println(answer);
}
public static void combination(int[][] arr, boolean[] visited, int depth, int last_pick, int D) {
if (depth == 3) {
int[][] new_arr = new int[arr.length][arr[0].length];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[0].length; j++) {
new_arr[i][j] = arr[i][j];
}
}
answer = Math.max(answer, simulation(new_arr, visited, D));
return;
}
for (int i = last_pick + 1; i < visited.length; i++) {
visited[i] = true;
combination(arr, visited, depth + 1, i, D);
visited[i] = false;
}
}
public static int simulation(int[][] arr, boolean[] visited, int D) {
int kill = 0;
// arr.length번 돌기
for (int time = 0; time < arr.length; time++) {
// 공격 후 적이동
ArrayList<Point> enemies = new ArrayList<>();
// 사람 돌며 적 찾기
for (int j = 0; j < visited.length; j++) {
if (visited[j]) {
enemies.add(find_enemy(arr, D, j));
}
}
for (Point enemy : enemies) {
if (enemy != null && arr[enemy.y][enemy.x] == 1) {
arr[enemy.y][enemy.x] = 0;
kill++;
}
}
for (int i = arr.length - 1; i > 0; i--) {
for (int j = 0; j < arr[0].length; j++) {
arr[i][j] = arr[i - 1][j];
}
}
for (int j = 0; j < arr[0].length; j++) {
arr[0][j] = 0;
}
}
return kill;
}
public static Point find_enemy(int[][] arr, int D, int j) {
Queue<Point> queue = new LinkedList<>();
boolean[][] visited = new boolean[arr.length][arr[0].length];
queue.add(new Point(arr.length - 1, j));
visited[arr.length - 1][j] = true;
while (!queue.isEmpty()) {
Point tmp = queue.remove();
if (Math.abs(arr.length - tmp.y) + Math.abs(j - tmp.x) > D)
break;
if (arr[tmp.y][tmp.x] == 1)
return tmp;
// 왼쪽
if (tmp.x - 1 >= 0 && !visited[tmp.y][tmp.x - 1]) {
visited[tmp.y][tmp.x - 1] = true;
queue.add(new Point(tmp.y, tmp.x - 1));
}
// 위
if (tmp.y - 1 >= 0 && !visited[tmp.y - 1][tmp.x]) {
visited[tmp.y - 1][tmp.x] = true;
queue.add(new Point(tmp.y - 1, tmp.x));
}
// 오른쪽
if (tmp.x + 1 < arr[0].length && !visited[tmp.y][tmp.x + 1]) {
visited[tmp.y][tmp.x + 1] = true;
queue.add(new Point(tmp.y, tmp.x + 1));
}
}
return null;
}
}