Skip to content

Commit f8c484e

Browse files
committed
[Unrated] Title: [모의 SW 역량테스트] 벽돌 깨기, Time: 176 ms, Memory: 45,312 KB -BaekjoonHub
1 parent d98e864 commit f8c484e

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# [Unrated] [모의 SW 역량테스트] 벽돌 깨기 - 5656
2+
3+
[문제 링크](https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRQm6qfL0DFAUo)
4+
5+
### 성능 요약
6+
7+
메모리: 45,312 KB, 시간: 176 ms, 코드길이: 4,196 Bytes
8+
9+
### 제출 일자
10+
11+
2023-10-10 11:34
12+
13+
14+
15+
> 출처: SW Expert Academy, https://swexpertacademy.com/main/code/problem/problemList.do
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import java.io.*;
2+
import java.util.*;
3+
4+
public class Solution {
5+
6+
static int N, W, H, min;
7+
8+
static class Point {
9+
int r, c, cnt; // 벽돌의 위치, 크기
10+
11+
Point(int r, int c, int cnt){
12+
super();
13+
this.r = r;
14+
this.c = c;
15+
this.cnt = cnt;
16+
}
17+
}
18+
19+
static int[] dx = {-1, 0, 1, 0};
20+
static int[] dy = {0, -1, 0, 1};
21+
22+
public static void main(String[] args) throws IOException {
23+
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
24+
int TC = Integer.parseInt(br.readLine());
25+
for(int tc = 1; tc <= TC; tc++) {
26+
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
27+
N = Integer.parseInt(st.nextToken()); // 구슬 던지는 횟수
28+
W = Integer.parseInt(st.nextToken()); // 가로
29+
H = Integer.parseInt(st.nextToken()); // 세로
30+
int[][] map = new int[H][W];
31+
32+
for(int i = 0; i < H; i++) {
33+
st = new StringTokenizer(br.readLine(), " ");
34+
for(int j = 0; j < W; j++) {
35+
map[i][j] = Integer.parseInt(st.nextToken());
36+
}
37+
} // input 2 dimen array map
38+
39+
min = Integer.MAX_VALUE;
40+
drop(0, map);
41+
System.out.println("#"+tc+" "+min);
42+
}
43+
}
44+
45+
// 구슬 던지기 : 중복 순열
46+
private static boolean drop(int cnt, int[][] map) {
47+
// 구슬 떨어뜨리기, cnt : 직전까지 떨어뜨린 구슬 수
48+
// map : 직전 상태까지의 map
49+
// return : 모든 벽돌이 제거되었는지 여부
50+
51+
// 구슬을 던지기 전에 현 상태로 남은 벽돌 수 체크
52+
int result = getRemain(map);
53+
54+
if(result == 0) {
55+
min = 0;
56+
return true;
57+
}
58+
59+
if(cnt == N) {
60+
if(min > result)
61+
min = result;
62+
return false;
63+
}
64+
// 남은 벽돌 수가 0이면 모든 벽돌이 제거된 가장 최적의 상태이므로 최소값 0으로 갱신 후 true를 리턴
65+
66+
// base condition : 모든 구슬을 다 던졌을 경우 남은 벽돌 수로 최소값 갱신 후 return false
67+
// false를 리턴하는 이유는 모든 벽돌들이 전부 부숴진 것은 아니기 때문이다.
68+
69+
int[][] newMap = new int[H][W];
70+
for(int c = 0; c < W; c++) {
71+
// 해당 열에 떨어뜨릴 경우 제거되는 맨 윗 벽돌 찾기
72+
int r = 0;
73+
while(r < H && map[r][c] == 0)
74+
r++;
75+
// 벽돌이 존재하지 않는다면(해당 열은 모두 빈칸) 다음 열로 건너 뛰기
76+
if(r == H)
77+
continue;
78+
79+
// 벽돌이 존재한다면
80+
copy(map, newMap);
81+
// 함께 제거될 인접 벽돌 연쇄 찾기
82+
boom(newMap, r, c);
83+
// 제거 처리(벽돌 내리기)
84+
// 디버깅 출력
85+
down(newMap);
86+
// 디버깅 출력
87+
// 다음 구슬 던지러 가기 :
88+
// recursive call ==> 재귀호출의 결과가 true이면 가장 최적해의 상황이므로 true를 리턴
89+
if(drop(cnt+1, newMap))
90+
return true;
91+
}
92+
93+
return false;
94+
}
95+
96+
97+
// 인접한 제거 벽돌 찾기 : flood fill (4방 BFS)
98+
99+
private static void boom(int[][] map, int r, int c) {
100+
Queue<Point> queue = new ArrayDeque<>();
101+
102+
if(map[r][c] > 1)
103+
queue.offer(new Point(r, c, map[r][c]));
104+
105+
map[r][c] = 0; // visited
106+
107+
while(!queue.isEmpty()) {
108+
Point cur = queue.poll();
109+
110+
for(int d = 0; d < 4; d++) {
111+
int nx = cur.r;
112+
int ny = cur.c;
113+
114+
for(int i = 1; i < cur.cnt; i++) {
115+
nx += dx[d];
116+
ny += dy[d];
117+
118+
if(nx >= 0 && nx < H && ny >= 0 && ny < W && map[nx][ny] > 0) {
119+
if(map[nx][ny] > 1)
120+
queue.offer(new Point(nx, ny, map[nx][ny]));
121+
map[nx][ny] = 0; // visited
122+
}
123+
}
124+
}
125+
}
126+
} // end of boom
127+
128+
// 벽돌 내리기1 : 빈 자리 위쪽 벽돌 찾아 내리기
129+
// 벽돌 내리기2 : 매 열마다 맨 윗행부터 벽돌칸 모두 스택에 넣고 빈칸 만들기
130+
private static void down(int[][] map) {
131+
// 매 열 기준으로 내리기
132+
for(int c = 0; c < W; c++) {
133+
int r = H-1, nr = -1;
134+
while(r > 0) {
135+
if(map[r][c] == 0) { // 빈칸을 만남, 내릴 벽돌을 찾기!
136+
nr = r-1; // 바로 윗 행부터 동작
137+
while(nr > 0 && map[nr][c] == 0)
138+
--nr;
139+
140+
map[r][c] = map[nr][c];
141+
map[nr][c] = 0; // 빈칸 처리
142+
}
143+
if(nr == 0)
144+
break;
145+
146+
--r;
147+
}
148+
}
149+
}
150+
151+
// 배열 복사하기
152+
private static void copy(int[][] map, int[][] newMap){
153+
for(int r = 0; r < H; r++) {
154+
newMap[r] = Arrays.copyOf(map[r], W);
155+
}
156+
} // end of copy
157+
158+
159+
// 남은 벽돌 개수 구하기 : 매번 구슬 던지기 전에 사용할 목적
160+
private static int getRemain(int[][] map) {
161+
int cnt = 0;
162+
163+
for(int i = 0; i<H; i++) {
164+
for(int j = 0; j < W; j++) {
165+
if(map[i][j] > 0)
166+
cnt++;
167+
}
168+
}
169+
170+
return cnt;
171+
} // end of getRemain
172+
173+
// 디버깅용 : 상태 출력
174+
}

0 commit comments

Comments
 (0)