https://www.swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRQm6qfL0DFAUo
SW Expert Academy
SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!
www.swexpertacademy.com
1. 1 ≤ N ≤ 4
2. 2 ≤ W ≤ 12
3. 2 ≤ H ≤ 15
범위가 위와 같기 때문에 완전 탐색을 해주면 된다. 연쇄적으로 깨질 벽돌은 큐를 사용하여 관리해줬다.
풀이
- 벽돌을 깨는 경우를 모든 열에 대해서 구해준다.
- 열을 선택하면 그 열에서 구슬에 처음 닿을 벽돌(행)을 찾아준다.
- 이제 위에서 찾은 벽돌에서부터 해당 칸의 값-1만큼 연쇄적으로 깨 주고 빈 공간을 채워주어야 한다.
- 먼저 새로 배열을 만들어야 한다. (매번 깨지는 모양이 다르므로)
- 깨뜨릴 벽돌들(값이 2 이상)의 정보를 큐에 넣어주고 매번 큐에서 꺼내서 깨뜨린다. (값이 0인 경우는 그냥 넘어가고 1인 경우에는 해당 칸을 0으로 만든 후 넘어간다)
- 큐에 있는 벽돌들을 제거해줬으면 이제 빈 공간을 정리해준다.
- 빈칸을 채울 때는 모든 열에서 마지막 행부터 순차적으로 검사한다.
- 0인 곳(비어있는 곳)을 찾아서 더 위칸에서 0이 아닌 값을 찾아 옮겨준다.
- 위쪽 칸들이 모두 0인 경우에는 다음 열로 넘어간다.
- 다음 구슬을 쏘기 위해서 구슬을 쏜 횟수인 cnt값을 증가시킨 후 위의 과정을 반복한다.
- cnt값이 N이 되었다면 남은 벽돌의 최소 개수를 구해준다.
- 최솟값을 출력하거나 벽돌이 모두 깨져서 최솟값을 계산해주지 못하고 초기값인 경우에는 0을 출력한다.
import java.io.*;
import java.util.*;
public class Solution {
static class Pair {
int x;
int y;
int num;
Pair(int x, int y, int num) {
this.x = x;
this.y = y;
this.num = num;
}
}
static int N,W,H,min;
static Queue q;
static int[] dx = {1,-1,0,0};
static int[] dy = {0,0,1,-1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
for(int tc=1; tc<=T; tc++) {
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
W = Integer.parseInt(st.nextToken());
H = Integer.parseInt(st.nextToken());
int[][] map = new int[H][W];
for(int i=0; i<H; i++) {
st = new StringTokenizer(br.readLine());
for(int j=0; j<W; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
min = -1;
solve(0,map);
if(min == -1) //벽돌이 모두 깨진 경우
System.out.println("#"+tc+" "+0);
else
System.out.println("#"+tc+" "+min);
}
}
static void solve(int cnt, int[][] arr) {
if(cnt == N) {
int remain = 0;
for(int i=0; i<H; i++) {
for(int j=0; j<W; j++) {
if(arr[i][j] != 0)
remain++;
}
}
if(min == -1 || min > remain)
min = remain;
return;
}
//모든 열에 대하여 구슬을 쏘는 경우를 구해준다.
for(int j=0; j<W; j++) {
int i = 0;
while(i < H) {
if(arr[i][j] != 0) break;
i++;
}
if(i == H) continue; //해당 열이 모두 빈칸이라 다음 열로 넘어간다.
int[][] arr2 = copyArr(arr);
crush(i,j,arr2); //깨뜨리기
move(arr2); // 빈 칸 정리
solve(cnt+1,arr2); // 다음 구슬 쏘기
}
}
static void move(int[][] arr) {
for(int j=0; j<W; j++) {
for(int i=H-1; i>0; i--) {
if(arr[i][j] == 0) {
//빈 칸을 찾으면 해당 빈칸 보다 위쪽 칸을 검사한다.
int k = i-1;
while(k >= 0) {
if(arr[k][j] != 0) { //떠 있는 벽돌(빈 칸이 아닌 칸)을 발견하면
arr[i][j] = arr[k][j]; //아래로 옮겨주고
arr[k][j] = 0; //해당칸은 비워준다.
break;
}
k--; //위쪽 칸을 계속 검사
}
if(k == -1) break; // 위쪽칸들이 모두 0인 경우 해당 열을 더 검사할 필요가 없으므로 다음 열로 넘어간다.
}
}
}
}
static void crush(int x, int y, int[][] arr) {
q = new LinkedList();
q.add(new Pair(x,y,arr[x][y]));
arr[x][y] = 0;
while(!q.isEmpty()) {
Pair p = q.remove();
for(int i=0; i<4; i++) {
int nx = p.x;
int ny = p.y;
int num = p.num;
for(int j=0; j<num-1; j++) {
nx += dx[i];
ny += dy[i];
if(nx < 0 || nx >= H || ny < 0 || ny >= W) break;
if(arr[nx][ny] == 0) continue;
if(arr[nx][ny] > 1)
q.add(new Pair(nx,ny,arr[nx][ny]));
arr[nx][ny] = 0; //깨트리기
}
}
}
}
static int[][] copyArr(int[][] arr) {
int[][] newArr = new int[H][W];
for(int i=0; i<H; i++) {
for(int j=0; j<W; j++) {
newArr[i][j] = arr[i][j];
}
}
return newArr;
}
}
'SWEA > 모의 SW 역량테스트(JAVA)' 카테고리의 다른 글
| [SWEA] 4013. [모의 SW 역량테스트] 특이한 자석 (0) | 2019.05.15 |
|---|---|
| [SWEA] 5644. 무선 충전 (0) | 2019.05.10 |
| [SWEA] 2117. 홈 방범 서비스 (0) | 2019.05.09 |
| [SWEA] 1949. 등산로 조성 (0) | 2019.05.01 |
| [SWEA] 5658. 보물상자 비밀번호 (0) | 2019.04.30 |