기기

[ 백준 17135 ] 캐슬 디펜스 ( 자바 ) 본문

CS/알고리즘 풀이

[ 백준 17135 ] 캐슬 디펜스 ( 자바 )

notEmpty 2020. 2. 16. 21:52

[ 백준 17135 ] 캐슬 디펜스 ( java ) 

캐슬 디펜스는 성을 향해 몰려오는 적을 잡는 턴 방식의 게임이다. 게임이 진행되는 곳은 크기가 N×M인 격자판으로 나타낼 수 있다. 격자판은 1×1 크기의 칸으로 나누어져 있고, 각 칸에 포함된 적의 수는 최대 하나이다. 격자판의 N번행의 바로 아래(N+1번 행)의 모든 칸에는 성이 있다.

성을 적에게서 지키기 위해 궁수 3명을 배치하려고 한다. 궁수는 성이 있는 칸에 배치할 수 있고, 하나의 칸에는 최대 1명의 궁수만 있을 수 있다. 각각의 턴마다 궁수는 적 하나를 공격할 수 있고, 모든 궁수는 동시에 공격한다. 궁수가 공격하는 적은 거리가 D이하인 적 중에서 가장 가까운 적이고, 그러한 적이 여럿일 경우에는 가장 왼쪽에 있는 적을 공격한다. 같은 적이 여러 궁수에게 공격당할 수 있다. 공격받은 적은 게임에서 제외된다. 궁수의 공격이 끝나면, 적이 이동한다. 적은 아래로 한 칸 이동하며, 성이 있는 칸으로 이동한 경우에는 게임에서 제외된다. 모든 적이 격자판에서 제외되면 게임이 끝난다. 

게임 설명에서 보다시피 궁수를 배치한 이후의 게임 진행은 정해져있다. 따라서, 이 게임은 궁수의 위치가 중요하다. 격자판의 상태가 주어졌을 때, 궁수의 공격으로 제거할 수 있는 적의 최대 수를 계산해보자.

격자판의 두 위치 (r1, c1), (r2, c2)의 거리는 |r1-r2| + |c1-c2|이다.

입력
첫째 줄에 격자판 행의 수 N, 열의 수 M, 궁수의 공격 거리 제한 D가 주어진다. 둘째 줄부터 N개의 줄에는 격자판의 상태가 주어진다. 0은 빈 칸, 1은 적이 있는 칸이다.

출력
첫째 줄에 궁수의 공격으로 제거할 수 있는 적의 최대 수를 출력한다.

 

 

 

출처: 백준 코딩 테스트 연습, https://www.acmicpc.net/problem/17135

 

17135번: 캐슬 디펜스

첫째 줄에 격자판 행의 수 N, 열의 수 M, 궁수의 공격 거리 제한 D가 주어진다. 둘째 줄부터 N개의 줄에는 격자판의 상태가 주어진다. 0은 빈 칸, 1은 적이 있는 칸이다.

www.acmicpc.net

 

 

 

 

 

핵심 

1 궁수 배치 

전형적인 dfs로 3 궁수의 위치를 배치한다. 

 

 

 

2  적 제거 

거리 D 이내의 적 중 가까운 적을 제거한다. 또한, 거리가 같은 적이 여럿 있다면, 더 왼쪽의 적을 제거한다. 

무엇보다 3 궁수가 동시에 적을 때리기 때문에, 중복 처리가 필요하다. 대부분 여기서 틀렸을 듯 

 

 

제거 방법 1) D에 따른 dy, dx를 만들고, 적을 제거. dy는 가장 왼쪽부터 탐색하게 하여 탐색 중 처음으로 만나는 적이 제거할 적이다. 무엇보다 이 방법이 다른 방법에 비해 몇 배로 가장 빠르다.

 

제거 방법 2) hashset에 제거될 적들 저장하여 중복처리 

 

제거 방법 3) 제거될 적에 willDie를 표시하여 한 공격자가 모든 적을 탐색 후에 제거한다. 

 

 

 

 

 

 

추가적으로 더 궁금한 점 있으면 댓글 달아주세요

 

 

 

 

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
 
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input[] = br.readLine().split(" ");
        N = Integer.parseInt(input[0]);
        M = Integer.parseInt(input[1]);
        D = Integer.parseInt(input[2]);
        map = new int[N][M];
        selected = new boolean[M];
        
        es = new Enemy[N*M];
        o_es = new Enemy[N*M];
        esLen = 0;
        for(int i = 0 ; i < N ; i++) {
            input = br.readLine().split(" ");
            for(int j = 0 ; j < M ; j++) {
                map[i][j] = Integer.parseInt(input[j]);
                if(map[i][j] == 1 ) {
                    o_es[esLen] = new Enemy(i, j);
                    es[esLen] = new Enemy(i, j);
                    esLen++;
                }
            }
        }
        
        setAttack(0);
        System.out.println(max);
    }
    static int N, M, D;
    static int[][] map;
    
    static int max = Integer.MIN_VALUE;
    static int[] attackPos = new int[3];
    static boolean[] selected;
    static void setAttack(int pos) {
        
        if(pos == 3) {
            Enemy e, o_e;
            // 적 초기화 
            for(int ei = 0 ; ei < esLen ; ei++) {
                o_e = o_es[ei];
                e = es[ei];
                e.alive = true;
                e.willDie = false;
                e.y = o_e.y;
                e.x = o_e.x;
            }
            
            int cnt = 0;
            for(int turn = 0 ; turn < N ; turn++) {
                for(int a = 0 ; a < 3 ; a++) {
                    int target = -1;
                    // 모든 적 
                    for(int ei = 0 ; ei < esLen ; ei++) {
                        if(es[ei].alive) {
                            if(dis(N, attackPos[a], ei) <= D) {
                                if(target == -1) {
                                    target = ei;
                                }else {
                                    int td = dis(N, attackPos[a], target);
                                    int ed = dis(N, attackPos[a], ei);
                                    if(td > ed) {
                                        target = ei;
                                    }else if(td == ed && es[target].x > es[ei].x) {
                                        target = ei;
                                    }
                                }
                            }
                        }
                    }
                    // 선택한 적 죽을 것 
                    if(target != -1) {
                        es[target].willDie = true;
                    }
                }
                
                // 적 이동 및 죽임 
                for(int ei = 0 ; ei < esLen ; ei++) {
                    e = es[ei];
                    if(e.alive && e.willDie) {
                        cnt++;
                        e.alive = false;
                    }
                    if(e.alive) {
                        e.y++;
                        if(e.y == N)
                            e.alive = false;
                    }
                }  
            }
            if(max < cnt) {
                max = cnt;
            }   
            return;
        }
        
        for(int p = 0 ; p < M ; p++) {
            if(!selected[p]) {
                selected[p] = true;
                attackPos[pos] = p;
                setAttack(pos+1);
                selected[p] = false;
            }
        }
    }
    
    static int esLen;
    static Enemy[] es, o_es ;
    
    static class Enemy{
        int y, x;
        boolean willDie = false;
        boolean alive = true;
        public Enemy(int y, int x) {
            this.y = y;
            this.x = x;
        }
    }
    
    static int dis(int y, int x, int e) {
        return Math.abs(y-es[e].y) + Math.abs(x-es[e].x);
    }
}
 
cs