https://www.acmicpc.net/problem/17135
17135번: 캐슬 디펜스
첫째 줄에 격자판 행의 수 N, 열의 수 M, 궁수의 공격 거리 제한 D가 주어진다. 둘째 줄부터 N개의 줄에는 격자판의 상태가 주어진다. 0은 빈 칸, 1은 적이 있는 칸이다.
www.acmicpc.net
문제
캐슬 디펜스는 성을 향해 몰려오는 적을 잡는 턴 방식의 게임이다. 게임이 진행되는 곳은 크기가 N×M인 격자판으로 나타낼 수 있다. 격자판은 1×1 크기의 칸으로 나누어져 있고, 각 칸에 포함된 적의 수는 최대 하나이다. 격자판의 N번행의 바로 아래(N+1번 행)의 모든 칸에는 성이 있다.
성을 적에게서 지키기 위해 궁수 3명을 배치하려고 한다. 궁수는 성이 있는 칸에 배치할 수 있고, 하나의 칸에는 최대 1명의 궁수만 있을 수 있다. 각각의 턴마다 궁수는 적 하나를 공격할 수 있고, 모든 궁수는 동시에 공격한다. 궁수가 공격하는 적은 거리가 D이하인 적 중에서 가장 가까운 적이고, 그러한 적이 여럿일 경우에는 가장 왼쪽에 있는 적을 공격한다. 같은 적이 여러 궁수에게 공격당할 수 있다. 공격받은 적은 게임에서 제외된다. 궁수의 공격이 끝나면, 적이 이동한다. 적은 아래로 한 칸 이동하며, 성이 있는 칸으로 이동한 경우에는 게임에서 제외된다. 모든 적이 격자판에서 제외되면 게임이 끝난다.
게임 설명에서 보다시피 궁수를 배치한 이후의 게임 진행은 정해져있다. 따라서, 이 게임은 궁수의 위치가 중요하다. 격자판의 상태가 주어졌을 때, 궁수의 공격으로 제거할 수 있는 적의 최대 수를 계산해보자.
격자판의 두 위치 (r1, c1), (r2, c2)의 거리는 |r1-r2| + |c1-c2|이다.
입력
첫째 줄에 격자판 행의 수 N, 열의 수 M, 궁수의 공격 거리 제한 D가 주어진다. 둘째 줄부터 N개의 줄에는 격자판의 상태가 주어진다. 0은 빈 칸, 1은 적이 있는 칸이다.
출력
첫째 줄에 궁수의 공격으로 제거할 수 있는 적의 최대 수를 출력한다.
제한
- 3 ≤ N, M ≤ 15
- 1 ≤ D ≤ 10
예제 입력 1
5 5 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 1 1
예제 출력 1
3
예제 입력 2
5 5 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
예제 출력 2
3
예제 입력 3
5 5 2
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
예제 출력 3
5
예제 입력 4
5 5 5
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
예제 출력 4
15
예제 입력 5
6 5 1
1 0 1 0 1
0 1 0 1 0
1 1 0 0 0
0 0 0 1 1
1 1 0 1 1
0 0 1 0 0
예제 출력 5
9
예제 입력 6
6 5 2
1 0 1 0 1
0 1 0 1 0
1 1 0 0 0
0 0 0 1 1
1 1 0 1 1
0 0 1 0 0
예제 출력 6
14
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int N;
static int M;
static int D;
static int[][] graph;
static int[][] copyGraph;
static int[] archer = new int[3];
static int result = 0;
private static void down() { // 적들이 아래로 한 칸 씩 이동하는 메소드
for (int i = N - 1; i > 0; i--) {
copyGraph[i] = copyGraph[i - 1];
}
copyGraph[0] = new int[M];
}
private static int[] attack(int y) { // y 위치에 있는 궁수가 공격할 적의 인덱스를 반환하는 메소드
for (int i = 1; i <= D; i++) { // 가장 가까운 적부터
for (int j = -i; j <= i; j++) { // 거리가 같다면 왼쪽부터
int ny = y + j;
int nx = N - i + Math.abs(j);
if(nx >= 0 && nx < N && ny >= 0 && ny < M && copyGraph[nx][ny] == 1) {
return new int[] {nx, ny};
}
}
}
return null;
}
private static void play() { // 궁수 3명이 N턴의 게임을 진행한다.
int[][] enemy = new int[3][2]; // 공격할 적의 위치
int count = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < 3; j++) { // 궁수 3명이 공격할 적들의 위치를 구한다.
enemy[j] = attack(archer[j]);
}
for (int j = 0; j < 3; j++) { // 한 명씩 공격
if(enemy[j] != null && copyGraph[enemy[j][0]][enemy[j][1]] == 1) { // 공격할 적이 없거나 이미 적이 죽은 경우가 아니면
copyGraph[enemy[j][0]][enemy[j][1]] = 0; // 적을 죽이고
count++; // 죽인 적의 수 카운트
}
} // 궁수 공격 끝
down(); // 적들 한 칸 이동
} // 적들이 N번 아래로 내려오면 게임 끝남
result = Math.max(result, count); // 현재 궁수의 위치가 가장 많은 적을 죽였다면 result 갱신
}
private static void pick(int n, int i) { // 궁수 3명의 자리를 고르는 메소드
if(n == 3) { // 궁수 3명 다 골랐다면
// graph deep copy
copyGraph = new int[N][M];
for (int j = 0; j < N; j++) {
copyGraph[j] = graph[j].clone();
}
play(); // 게임 시작
return;
}
for (int j = i; j < M; j++) {
archer[n] = j;
pick(n + 1, j + 1);
}
}
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
// 행의 수 N, 열의 수 M, 공격 거리 제한 D 입력
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
D = Integer.parseInt(st.nextToken());
// 격자판 상태 입력
graph = new int[N][M];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {
graph[i][j] = Integer.parseInt(st.nextToken());
}
}
// 궁수 3명 골라서 게임해본 뒤 최대값 구하기
pick(0, 0);
// 출력
System.out.println(result);
}
}'Problem Solving > BOJ' 카테고리의 다른 글
| [백준, BOJ 2606] 바이러스 (java) (0) | 2023.02.25 |
|---|---|
| [백준, BOJ 1987] 알파벳 (java) (0) | 2023.02.25 |
| [백준, BOJ 1260] DFS와 BFS (java) (0) | 2023.02.25 |
| [백준, BOJ 2957] 이진 탐색 트리 (java) (0) | 2023.02.25 |
| [백준, BOJ 7662] 이중 우선순위 큐 (java) (0) | 2023.02.22 |