|
| 1 | +import java.io.*; |
| 2 | +import java.util.*; |
| 3 | + |
| 4 | +/* |
| 5 | + * 고대 문명 유적 탐사 |
| 6 | + * step1에서 r과 c의 좌표를 for(int r = 1; r < 3; r++) 이렇게 해서 틀렸음 |
| 7 | + */ |
| 8 | + |
| 9 | +public class DH_고대_문명_유적_탐사 { |
| 10 | + static final int SIZE = 5, ROTATE_SIZE = 3; |
| 11 | + static int K, M; |
| 12 | + static int[][] map; // 유적지 정보 |
| 13 | + static int[] arr; // 조각 정보 |
| 14 | + static int result, IDX; // result: 각 턴마다 획득한 유물 가치의 총 합, IDX: 조각 정보의 인덱스 |
| 15 | + |
| 16 | + public static void main(String[] args) throws Exception { |
| 17 | + initInput(); |
| 18 | + solution(); |
| 19 | + } |
| 20 | + |
| 21 | + static void solution() { |
| 22 | + |
| 23 | + StringBuilder sb = new StringBuilder(); |
| 24 | + |
| 25 | + while(K-- > 0) { |
| 26 | + |
| 27 | + result = 0; |
| 28 | + |
| 29 | + // 탐사 진행 (1차 유물 획득을 최대로 할 수 있게) |
| 30 | + int[][] currentMap = step1(); |
| 31 | + |
| 32 | + // 1차 유물 획득 이후 빈 공간 채워주기 |
| 33 | + currentMap = fillMap(currentMap); |
| 34 | + |
| 35 | + // 회전을 안했다(획득한 가치가 0)면 탐사 종료 |
| 36 | + if(result == 0) break; |
| 37 | + |
| 38 | + int value = 0; |
| 39 | + |
| 40 | + // 유물 연쇄 획득 |
| 41 | + // 3개 이상 연결된거 찾아주고, 유적지 채워주기 |
| 42 | + while((value = getValue(currentMap)) != 0) { |
| 43 | + currentMap = fillMap(currentMap); |
| 44 | + result += value; |
| 45 | + } |
| 46 | + |
| 47 | + // 각 턴마다 afterStep1이라는 배열을 사용하고 있으므로 최종적으로 map배열을 currentMap으로 바꿔줌 |
| 48 | + map = currentMap; |
| 49 | + |
| 50 | + sb.append(result).append(" "); |
| 51 | + } |
| 52 | + System.out.println(sb); |
| 53 | + } |
| 54 | + |
| 55 | + static int[][] fillMap(int[][] map) { |
| 56 | + |
| 57 | + for(int c = 0; c < SIZE; c++) { |
| 58 | + for(int r = SIZE - 1; r >= 0; r--) { |
| 59 | + if(map[r][c] != 0) continue; |
| 60 | + |
| 61 | + map[r][c] = arr[IDX]; |
| 62 | + IDX = (IDX + 1) % M; |
| 63 | + } |
| 64 | + } |
| 65 | + return map; |
| 66 | + } |
| 67 | + |
| 68 | + static int[][] step1() { |
| 69 | + // (1) 유물 1차 획득 가치를 최대화하고 |
| 70 | + // (2) 회전 각도가 가장 작은 방법 |
| 71 | + // (3) 열이 가장 작으면서, (4) 행이 가장 작도록 |
| 72 | + int maxValue = Integer.MIN_VALUE; |
| 73 | + |
| 74 | + int[][] resultMap = new int[SIZE][SIZE]; |
| 75 | + |
| 76 | + for(int t = 0; t < 3; t++) { // (2) 회전한 각도가 가장 작은 |
| 77 | + for(int c = 1; c < 4; c++) { // (3) 중심 좌표의 열이 가장 작은 |
| 78 | + for(int r = 1; r < 4; r++) { // (4) 행이 가장 작은 |
| 79 | + int[][] tmp = rotate(r, c, t); |
| 80 | + |
| 81 | + int value = getValue(tmp); |
| 82 | + |
| 83 | + if(maxValue < value) { // (1) 유물 1차 획득 가치를 최대화 |
| 84 | + maxValue = value; |
| 85 | + resultMap = tmp; |
| 86 | + } |
| 87 | + } |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + result += maxValue; // 최대 유물 가치 더해주기 |
| 92 | + |
| 93 | + return resultMap; |
| 94 | + } |
| 95 | + |
| 96 | + static void print(int[][] arr) { |
| 97 | + System.out.println("map 출력 ----------"); |
| 98 | + for(int r = 0; r < arr.length; r++) { |
| 99 | + System.out.println(Arrays.toString(arr[r])); |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + static int[][] rotate(int r, int c, int t) { |
| 104 | + int[][] rotateMap = new int[SIZE][SIZE]; |
| 105 | + |
| 106 | + // 배열 복사 |
| 107 | + for(int cr = 0; cr < SIZE; cr++) rotateMap[cr] = Arrays.copyOf(map[cr], SIZE); |
| 108 | + |
| 109 | + // 회전 기준점을 (1, 1)로 놓고 회전 진행 |
| 110 | + for(int tr = -1; tr < 2; tr++) { |
| 111 | + for(int tc = -1; tc < 2; tc++) { |
| 112 | + int cr = r + tr, cc = c + tc; |
| 113 | + |
| 114 | + int tmp = map[cr][cc]; |
| 115 | + |
| 116 | + int sr = r - 1, sc = c - 1; |
| 117 | + |
| 118 | + int tmpR = r + tr - sr, tmpC = c + tc - sc; |
| 119 | + int nr = 0, nc = 0; |
| 120 | + |
| 121 | + // (r, c)를 기준으로 90도 회전 |
| 122 | + if(t == 0) { |
| 123 | + nr = tmpC; |
| 124 | + nc = (ROTATE_SIZE - 1) - tmpR; |
| 125 | + } |
| 126 | + |
| 127 | + // (r, c)를 기준으로 180도 회전 |
| 128 | + if(t == 1) { |
| 129 | + nr = ROTATE_SIZE - 1 - tmpR; |
| 130 | + nc = ROTATE_SIZE - 1 - tmpC; |
| 131 | + } |
| 132 | + |
| 133 | + // (r, c)를 기준으로 270도 회전 |
| 134 | + if(t == 2) { |
| 135 | + nr = ROTATE_SIZE - 1 - tmpC; |
| 136 | + nc = tmpR; |
| 137 | + } |
| 138 | + |
| 139 | + rotateMap[nr + sr][nc + sc] = tmp; |
| 140 | + } |
| 141 | + } |
| 142 | + |
| 143 | + return rotateMap; |
| 144 | + } |
| 145 | + |
| 146 | + static int[] dr = {-1, 1, 0, 0}, dc = {0, 0, -1, 1}; |
| 147 | + |
| 148 | + // bfs를 하면서 3개 이상 연속으로 있는 그룹 찾아주기 |
| 149 | + static int getValue(int[][] tmp) { |
| 150 | + |
| 151 | + int value = 0; |
| 152 | + boolean[][] v = new boolean[SIZE][SIZE]; |
| 153 | + |
| 154 | + for(int r = 0; r < SIZE; r++) { |
| 155 | + for(int c = 0; c < SIZE; c++) { |
| 156 | + if(v[r][c]) continue; |
| 157 | + |
| 158 | + Queue<Integer> q = new ArrayDeque<Integer>(); // bfs 탐색을 위한 큐 |
| 159 | + Queue<Integer> removeQ = new ArrayDeque<Integer>(); // 그룹이 생성된 후, 없앨 위치를 저장하기 위한 큐 |
| 160 | + |
| 161 | + v[r][c] = true; |
| 162 | + |
| 163 | + int currentValue = 1; |
| 164 | + int pos = r * SIZE + c; |
| 165 | + |
| 166 | + q.add(pos); |
| 167 | + removeQ.add(pos); |
| 168 | + |
| 169 | + while(!q.isEmpty()) { |
| 170 | + int currentPos = q.poll(); |
| 171 | + int cr = currentPos / SIZE, cc = currentPos % SIZE; |
| 172 | + |
| 173 | + for(int d = 0; d < 4; d++) { |
| 174 | + int nr = cr + dr[d]; |
| 175 | + int nc = cc + dc[d]; |
| 176 | + |
| 177 | + if(!check(nr, nc) || v[nr][nc] || tmp[nr][nc] != tmp[r][c]) continue; |
| 178 | + |
| 179 | + int nextPos = nr * SIZE + nc; |
| 180 | + q.add(nextPos); |
| 181 | + removeQ.add(nextPos); |
| 182 | + v[nr][nc] = true; |
| 183 | + currentValue += 1; |
| 184 | + } |
| 185 | + } |
| 186 | + |
| 187 | + if(currentValue < 3) continue; |
| 188 | + |
| 189 | + value += currentValue; |
| 190 | + |
| 191 | + while(!removeQ.isEmpty()) { |
| 192 | + int removePos = removeQ.poll(); |
| 193 | + int rr = removePos / SIZE; |
| 194 | + int rc = removePos % SIZE; |
| 195 | + |
| 196 | + tmp[rr][rc] = 0; |
| 197 | + } |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + return value; |
| 202 | + } |
| 203 | + |
| 204 | + static boolean check(int r, int c) { |
| 205 | + return r >= 0 && r < SIZE && c >= 0 && c < SIZE; |
| 206 | + } |
| 207 | + |
| 208 | + static void initInput() throws Exception { |
| 209 | + |
| 210 | + System.setIn(new FileInputStream("./input/고대문명유적탐사.txt")); |
| 211 | + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); |
| 212 | + StringTokenizer st = new StringTokenizer(br.readLine()); |
| 213 | + |
| 214 | + K = Integer.parseInt(st.nextToken()); // 탐사 반복 횟수 |
| 215 | + M = Integer.parseInt(st.nextToken()); // 유물 조각의 개수 |
| 216 | + |
| 217 | + arr = new int[M]; |
| 218 | + |
| 219 | + map = new int[SIZE][SIZE]; |
| 220 | + |
| 221 | + // 유적지 정보 |
| 222 | + for(int r = 0; r < map.length; r++) { |
| 223 | + st = new StringTokenizer(br.readLine()); |
| 224 | + |
| 225 | + for(int c = 0; c < map[0].length; c++) { |
| 226 | + map[r][c] = Integer.parseInt(st.nextToken()); |
| 227 | + } |
| 228 | + } |
| 229 | + |
| 230 | + st = new StringTokenizer(br.readLine()); |
| 231 | + |
| 232 | + // 유적 벽면에 써 있는 숫자 |
| 233 | + for(int i = 0; i < arr.length; i++) arr[i] = Integer.parseInt(st.nextToken()); |
| 234 | + } |
| 235 | +} |
0 commit comments