티스토리 뷰

algorithm/problem solving

BOJ 11559 Puyo Puyo

무니웜테일패드풋프롱스 2020. 5. 7. 14:31
 

11559번: Puyo Puyo

현재 주어진 상황에서 몇연쇄가 되는지 출력하라. (하나도 터지지 않는다면 0을 출력하면 된다.)

www.acmicpc.net

뿌요뿌요의 규칙

  • 상.하.좌.우 4개의 같은 색깔의 뿌요가 모이면 모두다 터진다.
  • 뿌요는 중력에 따라서 빈공간이 생기면 무조건 아래로 이동해야한다.
  • 여러색의 뿌요는 동시에 같은 연쇄에서 터질 수 있다.

세번째 조건은 백준의 유명한 BFS 문제인 토마토를 떠올릴 수 있다 .그러하다 나는 이 문제가 시뮬레이션이 들어간 토마토라고 생각했다.
물론 뿌요뿌요는, 상.하.좌.우 모두 무조건 터지는게 아니라 '같은 색'이어야만 터질 수 있으므로 BFS와 DFS를 모두 사용가능 하기도 하다.

그러면 일단 나의 로직은 이러하다.

  • 모든 색깔의 뿌요를 큐에 넣는다. 이 때 큐에 들어간 원소의 개수를 세준다.
  • 큐에 들어간 원소의 개수만큼 반복문을 실행한다. 큐에서 원소를 하나 씩 빼주며, 아직 터지지 않았을 경우 dfs를 실행해준다.
  • dfs에서는 상.하.좌.우를 탐색하되, 같은 색깔의 뿌요일 경우에만 탐색을 해준다. 탐색을 한번 할 때마다 터짐 갯수를 증가시켜준다.
  • dfs에서 터짐 갯수가 4개가 넘어가면, dfs 재귀가 끝나는 지점에 dfs에서 탐색된 모든 뿌요의를 visit 표시를 해준다. 더 이상 dfs를 진행할 수 없도록 말이다.
  • dfs가 끝나면 뿌요 터짐 횟수가 4개 이상이면 flag를 true로 해준다. 아무리 dfs를 실시해도 아무것도 터지지 않을 경우를 대비한다.
  • 큐에 들어간 원소의 개수만큼 반복문이 완료 되면, map을 업데이트 해준다.
  • 업데이트 한 맵에 따라서 다시 큐에 뿌요들을 넣어주고, 큐에 들어간 원소 수 만큼 반복문을 실시한다.
  • flag 가 true라면 연쇄 횟수를 늘려준다.
  • 큐에 아무것도 들어가지 않을 때 까지 혹은 더이상 터짐이 없을 때 까지 반복해준다.
import java.util.*;
import java.io.*;


class pair //큐에 저장 
{
    int x;
    int y;
    pair(int x, int y){
        this.x=x;
        this.y=y;
    }
}


public class Main {
    private static String[][] map;
    private static boolean[][] visit;
    private static boolean[][] check;
    private static int []dx = {-1,1,0,0};
    private static int[]dy= {0,0,-1,1};
    private static int queue_num=0;
    private static Queue<pair>queue = new LinkedList<>();
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        map = new String[12][6];
        visit= new boolean[12][6];
        check = new boolean[12][6];
        String[] s;
        for(int i= 0; i< 12; i++) {
            s = br.readLine().split("");
            for(int j=0; j<6; j++) {
                map[i][j]=s[j];
                if(!s[j].equals(".")) { //문자라면 큐에 저장해준다. 
                    queue.add(new pair(i,j));
                    queue_num++; //큐에 저장된 데이터 수 
                }
            }
        }
        System.out.println(solution());
    }
    static int puyo=0;
    private static void fill() {
        for(boolean a[]:check) {
            Arrays.fill(a, false);
        }
    }

    private static void update()  //맵 업데이트, 중력에 의해 뿌요들이 떨어진다.
    {
        for(int j=0; j<6; j++) { //자리이동 
            for(int i=11; i>=0; i--) 
            {
                if(visit[i][j] && !map[i][j].equals(".")) map[i][j]="."; //visit된 값들을 .으로 바꾸어준다. 
            }

            for(int i=11; i>=0; i--) 
            {
                if(map[i][j].equals(".") && visit[i][j]) 
                {
                    for(int k = i-1 ; k>=0; k--) 
                    {   //.으로 바꾼 값을 위에서 visited 안된 값으로 변경  (가장 가까운 값으로 변경..)
                        if(!visit[k][j] && !map[k][j].equals(".")) {
                            map[i][j]=map[k][j];
                            map[k][j]=".";
                            visit[i][j]=false;
                            visit[k][j]=true; //이 공간에도 다른 요소가 내려올 수 있도록!
                            break;
                        }
                    }
                }
            }
        }
    }

    private static void enqueue()  //업데이트 된 맵을 기준으로 큐에 다시 넣어주는 메서드 
    {
        boolean flag=false;
        for(int i = 0; i<=11; i++)  //큐에 다시 넣어준다. 
        {
            for(int j = 0; j<6 ; j++) 
            {
                if(!visit[i][j] && !map[i][j].equals(".")) {
                    queue.add(new pair(i,j));
                    queue_num++;
                }
            }
        }
    }

    private static int solution() {
        int n =0; // 연쇄 
        int count=0; //큐에 들어간만큼 
        boolean done=false; // 뿌요가 터졌는가? 
        while(!queue.isEmpty()) {  
            pair tmp = queue.poll(); //큐에서 꺼내준다. 
            count ++; //큐에서 꺼내준 만큼 카운팅 
            if(!visit[tmp.x][tmp.y]) {  //아직 visit이 안되었다면 dfs돌려준다. 
                dfs(tmp.x,tmp.y);
                if(puyo>=4) done=true; //puyo가 4이상이면 연쇄작용이 한번 이상 일어난 것으로 체크 
                puyo=0;  //puyo 초기화 
                fill(); //check 초기화 (dfs탐색을 위해) 
            }

            if(count == queue_num) { //모든 큐를 다 꺼냈다면 


                update(); //map을 업데이트해준다. 
                if(done) n++; //한번이라도 터졌다면 n++
                if(!done) return n; //안터졌다면 더 이상터질 수없으므로 끝 
                queue_num=0;
                enqueue();
                if(queue_num==0) return n; 
                done=false; 
                count =0;

            }

        }
        return n;
    }
    private static void dfs(int x , int y) 
    {
        String color=map[x][y];
        puyo++;
        check[x][y]=true;
        for(int i=0; i<4;i++) {
            int nx=x+dx[i];
            int ny=y+dy[i];
            if(nx < 0 || nx > 11 || ny <0 || ny >=6) continue;
            if(map[nx][ny].equals(color) && !check[nx][ny]) {
                dfs(nx,ny); //같은 색깔만 dfs를 해준다. 
            }
        }

        if(puyo>=4) {
            visit[x][y]=true;
        }
    }
}

'algorithm > problem solving' 카테고리의 다른 글

BOJ 2110 공유기 설치  (0) 2020.05.14
PROGRAMMERS level 2 프린터  (0) 2020.05.10
BOJ 2206 벽 부수고 이동하기  (0) 2020.05.05
BOJ 15686 치킨배달  (0) 2020.05.03
BOJ 2565 전깃줄  (0) 2020.04.17
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
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
글 보관함