[문제풀이] 밍이의 블록게임
업데이트:
문제 링크 : 밍이의 블록게임
풀이 시간 : 40분
1. 문제 풀이
간단한 시뮬레이션 문제
주어진 입력을 받고 입력에 따른 함수 처리를 하면 된다.
1) ‘U’ 입력 시
1.1) 새로운 줄을 추가할 수 있는지 체크(맨 위 줄에 블록이 있는지 체크)
1.2) 맨 위 줄에 블록이 있으면, 한 줄씩 복사 후 가장 마지막 줄은 새로운 줄 복사
1.3) 새로운 줄로 인한 빈 공간이 존재 시 처리(moveDown)
2) ‘L’ 입력 시
2.1) 왼쪽부터 빈 공간에 가장 가까운 블록 채워 넣기
1.2) 이동 후 블록이 원래 있던 위치 빈 공간 처리하기
3) ‘R’ 입력 시
3.1) 'L'과 동일한 방법으로 오른쪽부터 채우기
4) ‘D’ 입력 시
4.1) 블록 집합(인접한 같은 색깔의 블록들 집합) 찾기(BFS 방식)
4.2) 현재 탐색한 블록 집합이 최대 크기인지 비교
4.3) 클 경우 기존의 저장한 배열(store)을 비우고 현재 블록 집합 넣기
4.4) 같을 경우 기존의 저장한 배열(store)에 현재 블록 집합 추가
2. 소스 코드
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int iter = Integer.parseInt(br.readLine());
int[] dy = { 0, 0, -1, 1 };
int[] dx = { -1, 1, 0, 0 };
LinkedList<Point> q = new LinkedList<>();
LinkedList<Point> store = new LinkedList<>();
LinkedList<Point> tempStore = new LinkedList<>();
for (int i = 1; i <= iter; i++) {
// 입력 부분
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
int Q = Integer.parseInt(st.nextToken());
char[][] map = new char[N][M];
for (int j = 0; j < N; j++) {
map[j] = br.readLine().toCharArray();
}
// 각 버튼 클릭시
for (int j = 0; j < Q; j++) {
String s = br.readLine();
if (s.charAt(0) == 'U') {
boolean flag = true;
// 한 줄을 추가 할 수 있는지 판단
for (int k = 0; k < M; k++) {
// 제일 위에 블록이 있는지 판단
if (map[0][k] != '#') {
flag = false;
break;
}
}
// 한 줄이 추가 가능할때
if (flag) {
// 한줄씩 복사
for (int k = 0; k < N - 1; k++) {
map[k] = map[k + 1].clone();
}
// 맨 아래는 새롭게 들어오는 블록 추가
map[N - 1] = s.substring(2).toCharArray();
// 빈 공간 삭제
for (int k = 0; k < M; k++) {
if(map[N-1][k]=='#') {
for (int l = N-1; l >0; l--) {
map[l][k] = map[l-1][k];
map[l-1][k] = '#';
}
}
}
}
} else if (s.charAt(0) == 'L') {
// 왼쪽으로 밀기
for (int k = 0; k < N; k++) {
// 현재 행 중에서 빈 곳 중 가장 왼쪽 위치
int pivot = 0;
for (int l = 0; l < M; l++) {
if (map[k][l] != '#') {
char c = map[k][l];
map[k][l] = '#';
map[k][pivot] = c;
pivot++;
}
}
}
} else if (s.charAt(0) == 'R') {
// 오른쪽으로 밀기
for (int k = 0; k < N; k++) {
// 현재 행 중에서 빈 곳 중 가장 오른쪽 위치
int pivot = M - 1;
for (int l = M - 1; l >= 0; l--) {
if (map[k][l] != '#') {
char c = map[k][l];
map[k][l] = '#';
map[k][pivot] = c;
pivot--;
}
}
}
} else {
// 방문처리를 위한 배열
boolean[][] v = new boolean[N][M];
// 블록 집합 중 최대 크기
int max = 0;
// 최대 크기 블록 집합들의 위치 저장
store.clear();
for (int k = 0; k < N; k++) {
for (int l = 0; l < M; l++) {
// 블록이여서 방문하지 않은 블록 탐색
if (map[k][l] != '#' && !v[k][l]) {
// 시작하는 블록의 색깔
char c = map[k][l];
// 인접한 같은 색깔의 블록 리스트
q.clear();
q.add(new Point(k, l));
v[k][l] = true;
tempStore.clear();
while (!q.isEmpty()) {
Point p = q.poll();
// 현재 사용한 블록들 저장
tempStore.add(p);
// 인접한 블록 검색
for (int o = 0; o < 4; o++) {
int tempy = p.y + dy[o];
int tempx = p.x + dx[o];
// 방문하지 않았고 같은 색 블록 탐색
if (tempy >= 0 && tempy < N && tempx >= 0 && tempx < M && !v[tempy][tempx]
&& map[tempy][tempx] == c) {
v[tempy][tempx] = true;
q.add(new Point(tempy, tempx));
}
}
}
// 최대 블록 크기와 현재 진행한 블록 집합의 크기가 같거나 클 때
if (max <= tempStore.size()) {
// 클 때
if (max < tempStore.size()) {
// 최대 값 변경
max = tempStore.size();
// 기존에 저장한 블록 초기화
store.clear();
}
// 현재 블록들 저장
store.addAll(tempStore);
}
}
}
}
// 저장된 블록들 삭제
while(!store.isEmpty()) {
Point p = store.poll();
map[p.y][p.x] = '#';
}
// 빈 공간 삭제
for (int k = 0; k < map[0].length; k++) {
// 현재 행 중에서 빈 곳 중 가장 밑에 있는 위치
int pivot = map.length-1;
for (int l = map.length-1; l >=0; l--) {
if(map[l][k]!='#') {
char c = map[l][k];
map[l][k] = '#';
map[pivot][k] = c;
pivot--;
}
}
}
}
}
// 출력 저장
bw.write("#"+i);
bw.newLine();
for (int j = 0; j < map.length; j++) {
bw.write(map[j]);
bw.newLine();
}
bw.newLine();
}
bw.flush();
bw.close();
}
static class Point {
int y;
int x;
Point(int y, int x) {
this.y = y;
this.x = x;
}
}
3. 후기
오랜만에 SW Expert Academy를 풀었다.
다행히 한 번에 통과 되었지만 최적화를 한다고 여러번 제출했다.