목차
- 문제
- 내가 푼 방법
- 자바 코드
- 결과 및 회고
1. 문제
https://www.acmicpc.net/problem/17135
2. 내가 푼 방법
나는 각 턴마다 궁수를 죽이는 우선순위를 먼저 구한 후에 풀이를 진행했다. 여기서 턴은 마지막 적이 격자판을 넘어가 사라질 때까지의 과정을 얘기한다. (즉, 0 ~ N-1 차례가 있음)
따라서 아래 전역 변수들을 먼저 설명하자면, N, M, D는 문제에 나와있는 값들을 그대로 대입했고, arr 배열은 각 턴마다 적의 위치를 담은 Tuple 클래스 배열, dieTime 배열은 궁수가 각 턴에 적을 죽일 때 우선순위를 담고 있다.
Tuple 클래스는 적이므로, 각 적들마다 num 멤버 변수를 통해 고유값을 부여하고, far 멤버 변수를 통해 추후에 궁수와 적 사이의 거리를 구해줄 것이다.
static int N;
static int M;
static int D;
static LinkedList<Tuple>[] arr;
static List<Integer>[][] dieTime; // dieTime[x][y] : x가 y시간에 적을 죽일 때 우선순위
static int result;
public static class Tuple implements Comparable<Tuple>{
int x;
int y;
int num;
int far;
public Tuple(int x, int y, int num) {
this.x = x;
this.y = y;
this.num = num;
}
public Tuple(int x, int y, int num, int far) {
this.x = x;
this.y = y;
this.num = num;
this.far = far;
}
@Override
public int compareTo(Tuple t) {
if (t.far == this.far) return this.y - t.y;
return this.far - t.far;
}
}
메인의 solution 함수에서 moveEnemy() 함수를 통해 각 턴의 적들의 위치를 먼저 넣어준다. 그다음에 attackEnemy() 함수를 통해 각 턴마다 각각의 궁수가 적을 죽일 때 우선순위를 구한다.
dieTime[idx][x+1]는 (idx)번의 궁수가 (x+1)턴에 적을 죽이는 우선순위이다. 궁수와 적 사이의 거리가 D값 이하일 경우에만 죽일 수 있는 배열에 담아둔다.
public static void main (String[] args) throws IOException {
init();
solution();
print();
}
public static void solution() {
result = 0;
moveEnemy();
attackEnemy();
dfs(0, 0, new boolean[M]);
}
public static void moveEnemy() {
for (int z = 1; z < N; z++) {
for (Tuple t : arr[z-1]) {
if (t.x + 1 < N) {
arr[z].add(new Tuple(t.x + 1, t.y, t.num));
}
}
}
}
public static void attackEnemy() {
for (int i = 0; i < M; i++) {
// [N][i]에서 공격했을 때, 각 적들의 dieTime 구하기
bfs(i);
}
}
public static void bfs(int idx) {
for (int x = 0; x < N; x++) {
PriorityQueue<Tuple> queue = new PriorityQueue<>();
for (Tuple t : arr[x]) {
int far = Math.abs(t.x - N) + Math.abs(t.y - idx);
if (far <= D) queue.add(new Tuple(t.x, t.y, t.num, far));
}
while (!queue.isEmpty()) {
Tuple tuple = queue.poll();
dieTime[idx][x+1].add(tuple.num);
}
}
}
이제 최대 적을 제거할 수 있는 궁수를 고르기만 남았다.
따라서 solution 함수에서 dfs() 함수를 통해 경우의 수를 구하고 최대 죽일 수 있는 적을 result에 담아둔다.
cnt 값이 3이 될 경우, 선택했던 궁수를 getMaxAttack() 함수에 전달해주면서 최대 적을 구한다.
각 턴마다 궁수가 적을 죽이는데, 이미 죽은 적일 경우에는 다음 우선순위인 적을 죽여야 한다.
public static void dfs(int idx, int cnt, boolean[] choice) {
if (cnt == 3) {
List<Integer> tmp = new ArrayList<>();
for (int i = 0; i < choice.length; i++) {
if (choice[i]) tmp.add(i);
}
result = Math.max(result, getMaxAttack(tmp));
return;
}
if (idx == M) return;
dfs(idx+1, cnt, choice);
choice[idx] = true;
dfs(idx+1, cnt+1, choice);
choice[idx] = false;
}
public static int getMaxAttack(List<Integer> list) {
int cnt = 0;
boolean[] isDie = new boolean[arr[0].size()];
for (int i = 0; i <= N; i++) {
Set<Integer> tmp = new HashSet<>();
for (Integer idx : list) {
for (Integer enemy : dieTime[idx][i]) {
if (!isDie[enemy]) {
tmp.add(enemy);
break;
}
}
}
for (Integer enemy : tmp) {
cnt++;
isDie[enemy] = true;
}
}
return cnt;
}
3. 자바 코드
깃허브 풀이 주소
https://github.com/geujeog/BOJ/blob/main/B17135.java
import java.util.*;
import java.io.*;
class Main {
static int N;
static int M;
static int D;
static LinkedList<Tuple>[] arr;
static List<Integer>[][] dieTime; // dieTime[x][y] : x가 y시간에 적을 죽일 때 우선순위
static int result;
public static void main (String[] args) throws IOException {
init();
solution();
print();
}
public static void solution() {
result = 0;
moveEnemy();
attackEnemy();
dfs(0, 0, new boolean[M]);
}
public static void dfs(int idx, int cnt, boolean[] choice) {
if (cnt == 3) {
List<Integer> tmp = new ArrayList<>();
for (int i = 0; i < choice.length; i++) {
if (choice[i]) tmp.add(i);
}
result = Math.max(result, getMaxAttack(tmp));
return;
}
if (idx == M) return;
dfs(idx+1, cnt, choice);
choice[idx] = true;
dfs(idx+1, cnt+1, choice);
choice[idx] = false;
}
public static int getMaxAttack(List<Integer> list) {
int cnt = 0;
boolean[] isDie = new boolean[arr[0].size()];
for (int i = 0; i <= N; i++) {
Set<Integer> tmp = new HashSet<>();
for (Integer idx : list) {
for (Integer enemy : dieTime[idx][i]) {
if (!isDie[enemy]) {
tmp.add(enemy);
break;
}
}
}
for (Integer enemy : tmp) {
cnt++;
isDie[enemy] = true;
}
}
return cnt;
}
public static void attackEnemy() {
for (int i = 0; i < M; i++) {
// [N][i]에서 공격했을 때, 각 적들의 dieTime 구하기
bfs(i);
}
}
public static void bfs(int idx) {
for (int x = 0; x < N; x++) {
PriorityQueue<Tuple> queue = new PriorityQueue<>();
for (Tuple t : arr[x]) {
int far = Math.abs(t.x - N) + Math.abs(t.y - idx);
if (far <= D) queue.add(new Tuple(t.x, t.y, t.num, far));
}
while (!queue.isEmpty()) {
Tuple tuple = queue.poll();
dieTime[idx][x+1].add(tuple.num);
}
}
}
public static class Tuple implements Comparable<Tuple>{
int x;
int y;
int num;
int far;
public Tuple(int x, int y, int num) {
this.x = x;
this.y = y;
this.num = num;
}
public Tuple(int x, int y, int num, int far) {
this.x = x;
this.y = y;
this.num = num;
this.far = far;
}
@Override
public int compareTo(Tuple t) {
if (t.far == this.far) return this.y - t.y;
return this.far - t.far;
}
}
public static void moveEnemy() {
for (int z = 1; z < N; z++) {
for (Tuple t : arr[z-1]) {
if (t.x + 1 < N) {
arr[z].add(new Tuple(t.x + 1, t.y, t.num));
}
}
}
}
public static void print() throws IOException {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write(result+"");
bw.flush();
bw.close();
}
public static void init() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
D = Integer.parseInt(st.nextToken());
arr = new LinkedList[N];
dieTime = new LinkedList[M][N+1];
for (int i = 0; i < N; i++) {
arr[i] = new LinkedList<>();
}
for (int i = 0; i < M; i++) {
for (int j = 0; j <= N; j++) {
dieTime[i][j] = new LinkedList<>();
}
}
int cnt = 0;
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {
if (Integer.parseInt(st.nextToken()) == 1) arr[0].add(new Tuple(i, j, cnt++));
}
}
br.close();
}
}
4. 결과 및 회고
꽤 길었던 풀이였던 것 같다. 풀이가 길어질수록 내가 선언했던 변수들에 대한 설정도 잘 기억해야 한 것 같다.
그래서 풀이에서 dieTime[x][y]가 궁수 x가 y턴에 죽일 수 있는 적의 우선순위을 담아두었다고 강조했던 것이었다.ㅎㅎ
'문제풀이 > 백준' 카테고리의 다른 글
[JAVA] BOJ 백준 2615번 - 오목 (0) | 2023.10.01 |
---|---|
[JAVA] BOJ 백준 5525번 - IOIOI (1) | 2023.10.01 |
[JAVA] BOJ 백준 2011번 - 암호코드 (0) | 2023.09.27 |
[JAVA] BOJ 백준 16928번 - 뱀과 사다리 게임 (0) | 2023.09.27 |
[JAVA] BOJ 백준 15684번 - 사다리 조작 (0) | 2023.09.27 |
댓글