https://www.acmicpc.net/problem/17135
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.StringTokenizer;
public class Main {
static int[][] map;
static int N, M, D, maxKill = 0;
static List<int[]> enemies = new ArrayList<>();
static int ivy = 0;
public static void main(String[] args) throws Exception{
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());
map = new int[N+1][M];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
if(map[i][j] == 1)
enemies.add(new int[] {i, j});
}
}
int[] archerPos = new int[3];
setArcher(0, 0, archerPos);
System.out.println(maxKill);
}
private static void setArcher(int idx, int cnt, int[] archerPos) {
if(cnt == 3) {
ivy++;
maxKill = Math.max(maxKill, playGames(archerPos));
return;
}
for (int i = idx; i < M; i++) {
archerPos[cnt] = i;
setArcher(idx+1, cnt+1, archerPos);
}
}
private static List<int[]> copy(List<int[]> list) {
List<int[]> tmp = new ArrayList<>();
for(int[] p : list) {
tmp.add(new int[] {p[0], p[1]});
}
return tmp;
}
private static int playGames(int[] archerPos) {
int[][] cMap = new int[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cMap[i][j] = map[i][j];
}
}
//적 위치 복사
List<int[]> eList = copy(enemies);
int cnt = 0;
//archer위치 기준으로 제거
while(true) {
//적 없으면 멈춤
if(eList.isEmpty()) break;
Set<int[]> target = new HashSet<>();
//궁수 3명 한 명씩 돌아가며 처리
for (int l = 0; l < 3; l++) {
PriorityQueue<Enemy> pq = new PriorityQueue<Main.Enemy>();
boolean[][] kill = new boolean[N][M];
int ay = archerPos[l];
//가능한 적들 저장
for(int[] e : eList) {
int dist = Math.abs(N - e[0]) + Math.abs(ay - e[1]);
if(dist <= D)
pq.add(new Enemy(e[0], e[1], dist));
}
//제일 가까운 적 죽임
if(!pq.isEmpty()) {
Enemy e = pq.poll();
if(!kill[e.x][e.y]) {
target.add(new int[] {e.x, e.y});
kill[e.x][e.y] = true;
}
}
}
//3명의 목표물 삭제
int k = 0;
for(int[] t : target) {
//System.out.printf("<<%d %d>> x : %d, y: %d\n",ivy, k++, t[0], t[1]);
for (int i = eList.size()-1; i >= 0; i--) {
if(t[0] == eList.get(i)[0] && t[1] == eList.get(i)[1]) {
eList.remove(i);
cnt++;
break;
}
}
}
//한 칸 이동
for (int i = eList.size()-1; i >= 0; i--) {
eList.get(i)[0] += 1;
if(eList.get(i)[0] == N)
eList.remove(i);
}
}
return cnt;
}
private static class Enemy implements Comparable<Enemy>{
int x, y;
int dist;
Enemy(int x, int y, int dist) {
this.x = x;
this.y = y;
this.dist = dist;
}
@Override
public int compareTo(Enemy o) {
if(this.dist == o.dist)
return this.y - o.y;
return this.dist - o.dist;
}
}
}
💡 백트레킹(조합), 시뮬레이션, 구현
풀이
푸는데 진빠지는 문제,,, 조건이 까다롭고 좌표 다룰 때 중복 처리랑 제거가 어려웠다.
문제는 아래와 같은 방식으로 풀이가 진행된다.
- 처음 map 정보를 저장할 때, 적의 위치를 int[] 배열 형태로 저장 (얘네만 고려하면 됨)
- 조합(백트레킹)을 사용해 궁수 3명의 위치를 배열에 저장하고, 그것을 토대로 시뮬레이션을 돌린다.
- 이때 궁수의 위치의 x좌표는 어차피 N+1(map에선 N)로 동일하기 때문에 1차원 배열에 y 좌표 위치만 저장
- 시뮬레이션을 돌릴 때, 적군 위치 리스트 먼저 복사한 뒤, 궁수 3명에 대해 각각 제일 가까운 적 위치 저장
- 제일 가까운 적은 거리(dist)가 가까운 순서, 거리가 같다면 y값이 작은 순서대로 오름차순 정렬
- 그러므로 영향권 내 모든 적들의 위치를 우선순위 큐에 저장한 뒤, 해당 조건을 기준으로 정렬함
- 적 위치 저장 끝나면, 제일 가까운 적 한명
- 궁수 3명에 대해 각각 다 구했으면, 그 target 안 적군들을 리스트에서 삭제 후, 나머지 적군은 한 칸씩 전진
- 배열은 set에 넣어도 중복처리가 안되므로 boolean[][]배열을 자체적으로 만들어 중복 방지 해줌
- 남은 적군 List를 순회하며, 판 밖으로 나온 적들은 삭제함
- 이때, List를 순회 + 제거를 함께 해야 하므로 뒤에서부터 진행함 (idx 에러 방지)
Set<int[]>가 중복 제거가 안되는 이유
기시감이 든다 했더니 전에도 비슷한걸로 틀림..ㅋ.ㅋ ...
- Set의 중복확인 방법 : equals( ), hashCode( ) 메서드를 사용한다.
-> 이때 배열은 equals( ), hashCode( )가 배열의 내용이 아닌 객체의 참조를 기반으로 동작한다
즉, 배열에 아무리 같은 값이 들어있다고 해도, 그 배열의 메모리 주소를 비교하므로 다른 취급함!
- 객체도 당연히 마찬가지....
- 그렇기에 Set을 이용할 때 boolean 배열을 사용해 중복인지 별도로 체크해줬다.
- Set의 기능을 이용하고 싶다면?
1) int[] 배열 대신 List로 정의한다 (List는 중복 구분함)
2) 배열을 사용자 정의 객체로 감싸서 equals( ), hashCode( ) 메서드를 재정의해줌
'Algorithm > Beakjoon' 카테고리의 다른 글
[JAVA] 백준 17951번 : 흩날리는 시험지 속에서 내 평점이 느껴진거야 (0) | 2024.05.18 |
---|---|
[JAVA] 백준 17281번 : ⚾ (0) | 2024.05.17 |
[JAVA] 백준 1106번 : 호텔 (0) | 2024.05.15 |
[JAVA] 백준 9084번 : 동전 (0) | 2024.05.13 |
[JAVA] 백준 14567번 : 선수과목 (Prerequisite) (0) | 2024.05.12 |