-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSWEA_5656_벽돌깨기.java
162 lines (140 loc) · 3.96 KB
/
SWEA_5656_벽돌깨기.java
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
/**
* @author rodash3
* @since 2020. 3. 14.
* @see https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRQm6qfL0DFAUo
* @memory 100076 KB
* @time 282 ms
* @caution 중복순열을 통해 구슬 떨어뜨릴 위치(열)를 뽑는다
* 뽑은 위치에 따라 구슬을 떨어뜨려 벽돌을 제거하고 빈공간을 내리는 작업을 N번 반복
* 다 떨어뜨린 후 각 경우마다 벽돌의 개수를 세어서 최솟값을 찾는다
*/
public class SWEA_5656_벽돌깨기 {
static int N, W, H;
static int[][] map; //H행 W열
static int[][] tmap;
static int MIN; // 남은 벽돌 개수
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int TC = Integer.parseInt(st.nextToken());
for(int i=1; i<=TC; i++) {
//input
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
W = Integer.parseInt(st.nextToken());
H = Integer.parseInt(st.nextToken());
map = new int[H][W];
for(int r=0; r<H; r++) {
st = new StringTokenizer(br.readLine());
for(int c=0; c<W; c++) {
map[r][c] = Integer.parseInt(st.nextToken());
}
}//input over
MIN = Integer.MAX_VALUE;
combination(0, new int[N]);
System.out.println("#"+i+" "+MIN);
}
}
// 구슬 떨어뜨리기
public static void dropBeads(int[] temp) {
// 맵 복사
tmap = new int[H][W];
for(int r=0; r<H; r++) {
tmap[r] = map[r].clone();
}
// N번 구슬 떨어뜨리고 빈공간 내리기
for(int t: temp) {
breakBricks(t);
fallBricks();
}
//남은 벽돌 개수 구하기
int cnt = 0;
for(int r=0; r<H; r++) {
for(int c=0; c<W; c++) {
if(tmap[r][c] > 0) cnt++;
}
}
MIN = Math.min(cnt, MIN);
}
// w열에 구슬이 떨어짐, 벽돌 제거
public static void breakBricks(int w) {
Queue<Dot> queue = new LinkedList<>();
// 맨 위의 벽돌 큐에 넣기
for(int r=0; r<H; r++) {
if(tmap[r][w] != 0) {
queue.offer(new Dot(r, w, tmap[r][w]));
tmap[r][w] = 0;
break;
}
}
// bfs
while(!queue.isEmpty()) {
Dot front = queue.poll();
// 상하좌우 0으로 만들기
for(int d=0; d<4; d++) {
// 벽돌에 적힌 숫자 - 1 칸 만큼 제거
for(int i=1; i<front.n; i++) {
int nx = front.x + dx[d]*i;
int ny = front.y + dy[d]*i;
if(isIn(nx, ny)) {
if(tmap[nx][ny] > 1)
queue.offer(new Dot(nx, ny, tmap[nx][ny]));
if(tmap[nx][ny] > 0)
tmap[nx][ny] = 0;
}
}
}
}//while over
}
// 벽돌이 제거되고 난 후 빈공간이 있을 경우 벽돌은 밑으로 떨어짐
public static void fallBricks() {
for(int c=0; c<W; c++) {
int bottom = H-1;
// 각 열마다 바닥 행부터 탐색
for(int r=H-1; r>=0; r--) {
if(bottom == r && tmap[r][c] > 0) {
bottom--;
}
// 내려야함
if(bottom > r && tmap[r][c] > 0) {
tmap[bottom][c] = tmap[r][c];
tmap[r][c] = 0;
bottom--;
}
}
}
}
// 중복순열로 구슬 떨어뜨릴 위치 뽑기
public static void combination(int k, int[] temp) {
if(k==N) {
if(MIN == 0) return;
dropBeads(temp);
}else {
for(int i=0; i<W; i++) {
temp[k] = i;
combination(k+1, temp);
}
}
}
static int[] dx = {1, -1, 0, 0};
static int[] dy = {0, 0, -1, 1};
static boolean isIn(int x, int y) {
return x>=0 && y>=0 && x<H && y<W;
}
static class Dot{
int x;
int y;
int n; // 벽돌에 적힌 숫자
public Dot(int x, int y, int n) {
this.x = x;
this.y = y;
this.n = n;
}
}
}