본문 바로가기
Algorithm/백준풀이

[알고리즘 문제풀이] 백준 21611 마법사 상어와 블리자드(JAVA코드)

by 계범 2022. 4. 1.

목차

    https://www.acmicpc.net/problem/21611

     

    21611번: 마법사 상어와 블리자드

    마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그, 비바라기 마법을 할 수 있다. 오늘 새로 배운 마법은 블리자드이고, 크기가 N×N인 격자에서 연습하려고 한다. N은 항상 홀수이고, (

    www.acmicpc.net

    /**
     * 1. 맵 생성
     * 
     * 2. 각 모듈화를 통해 구현할 예정
     */
    
    import java.util.*;
    import java.io.*;
    
    public class 마법사상어와블리자드 {
        public static int n,m, result,sx,sy;
        public static ArrayList<int[]> numberMap = new ArrayList<>();
        public static int[][] beadMap;
        public static int[][] dirXY = {{-1,0},{1,0},{0,-1},{0,1}};
        public static int[] boomBead = new int[4];
        public static Queue<int[]> q;
        public static void main(String[] args) throws IOException{
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		
            StringTokenizer st = new StringTokenizer(br.readLine());
            n = Integer.parseInt(st.nextToken());
            m = Integer.parseInt(st.nextToken());
    
            beadMap = new int[n][n];
    
            // 초기 구슬맵 채우기
            for(int i = 0; i < n; i++){
                st = new StringTokenizer(br.readLine());
                for(int j = 0; j < n; j++){
                    beadMap[i][j] = Integer.parseInt(st.nextToken());
                }
            }
    
            initNumberMap(); // 번호맵 채우기
    
            for(int i = 0; i < m; i++){
                st = new StringTokenizer(br.readLine());
                int d = Integer.parseInt(st.nextToken()) -1;
                int s = Integer.parseInt(st.nextToken());
                blizard(d,s); // 마법 사용
                moveBead(); // 이동
                while(true){
                    if(groupBead() == false){ // 폭파 그룹 확인 및 폭파
                        break;
                    }
                    moveBead(); // 이동
                }
                changeBead(); // 구슬 변화
            }
    
            System.out.println(boomBead[1]*1 + boomBead[2]*2 + boomBead[3]*3); // 폭파 구슬 더해서 출력
        }
    
        // public static void printMap(){
        //     System.out.println("--------------------");
        //     for(int i = 0; i < n; i++){
        //         for(int j = 0; j < n; j++){
        //             System.out.print(beadMap[i][j] +" ");
        //         }
        //         System.out.println();
        //     }
        //     System.out.println("--------------------");
        // }
    
    
        //구슬 변화 함수
        public static void changeBead(){
    
            int num = 0;
            int cnt = 0;
            int[][] newMap = new int[n][n]; // 변화된 구슬들 담을 맵
    
            ArrayList<Integer> beadCntNum = new ArrayList<>(); // 동일 번호 구슬 개수와 번호 담기
            for(int i = 0; i < numberMap.size(); i++){ // 맵 전체 순서대로 돌기
                int x = numberMap.get(i)[0];
                int y = numberMap.get(i)[1];
    
                if(beadMap[x][y] == 0){ //더 이상 구슬 없으면 종료
                    break;
                }
    
                if(num != 0 && num != beadMap[x][y]){ // 기존 구슬과 번호가 달라지면 담기
                    beadCntNum.add(cnt);
                    beadCntNum.add(num);
                    cnt = 0;
                }
                cnt++;
                num = beadMap[x][y];
            }
    
            if(num != 0){ // 마지막꺼 담기
                beadCntNum.add(cnt);
                beadCntNum.add(num);
            }
    
            int idx = 0;
            for(int i = 0; i < beadCntNum.size(); i++){ // 담았던 구슬 개수와 번호들을 입력
                int x = numberMap.get(idx)[0];
                int y = numberMap.get(idx)[1];
    
                newMap[x][y] = beadCntNum.get(i);
                idx++;
                if(idx >= numberMap.size()){ // 맵 범위 넘어가면 종료
                    break;
                }
            }
            beadMap = newMap; // 변화된 구슬로 맵 변경
        }
    
        // 폭파 구슬그룹 체크 및 폭파 함수
        public static boolean groupBead(){
            boolean check = false;
            ArrayList<int[]> curGroup = new ArrayList(initialCapacity)<>(); // 현재 그룹
            ArrayList<int[]> boomGroup = new ArrayList<>(); // 폭파할 그룹
    
            int beadNum = 0; // 구슬번호
            int cnt = 0; // 개수
            for(int i = 0; i < numberMap.size(); i++){
                int x = numberMap.get(i)[0];
                int y = numberMap.get(i)[1];
                
                if(beadMap[x][y] == beadNum && beadMap[x][y] != 0){
                    cnt++;
                }else{
                    if(cnt >= 4){ // 현재 그룹이 4개이상이면 폭파 그룹에 담기
                        boomGroup.addAll(curGroup); // 좌표들 폭파 그룹에 담기
                        check = true; // 한번 이상 폭파됨
                    }
                    if(beadMap[x][y] == 0){ // 더이상 구슬이 없으면 종료
                        break;
                    }
                    curGroup.clear();
                    cnt = 1;
                }
                curGroup.add(new int[] {x,y}); // 현재 좌표를 담기
                beadNum = beadMap[x][y];
            }
    
            if(cnt >= 4){ // 마지막꺼 체크
                boomGroup.addAll(curGroup);
                check = true;
            }
    
            if(check){ // 폭파할 그룹이 있으면 폭파
                for(int i = 0; i < boomGroup.size(); i++){
                    int x = boomGroup.get(i)[0];
                    int y = boomGroup.get(i)[1];
    
                    int num = beadMap[x][y];
                    boomBead[num]++; // 폭파 개수 늘리기
                    beadMap[x][y] = 0; // 폭파해서 빈칸으로 바꾸기
                }
            }
    
            return check;
        }
    
        // 구슬 이동 함수
        public static void moveBead(){
            int pidx = 0; // 빈칸 좌표
            int idx = 1; // 구슬 가져올 좌표
    
            while(idx < numberMap.size()){ // 맵 벗어나기전까지만 체크
    
                // 빈칸 좌표
                int x = numberMap.get(pidx)[0];
                int y = numberMap.get(pidx)[1];
    
                // 구슬 가져올 좌표
                int nx = numberMap.get(idx)[0];
                int ny = numberMap.get(idx)[1];
    
                //해당 좌표가 빈칸일때
                if(beadMap[x][y] == 0){
                    if(beadMap[nx][ny] == 0){ // 구슬 가져올 좌표가 빈칸이면 다음좌표 확인.
                        idx++;
                        continue;
                    }
                    beadMap[x][y] = beadMap[nx][ny]; // 구슬 이동
                    beadMap[nx][ny] = 0;
                }
    
                pidx++; // 빈칸이 아니면 다음 좌표 확인
    
                if(pidx == idx){ // 숫자가 더 큰 좌표에서만 가져올 수 있으므로 같아지면 증가.
                    idx++;
                }
            }
        }
    
        // 마법 사용 함수
        public static void blizard(int d, int s){
            for(int i = 1; i <= s; i++){ // 거리만큼 돌면서 구슬 지우기
                int x = sx + dirXY[d][0]*i; // 해당 방향, 해당 거리 구슬 좌표
                int y = sy + dirXY[d][1]*i;
    
                if(x < 0 || x >= n || y < 0 || y >= n){ // 맵 벗어나면 종료
                    break;
                }
                beadMap[x][y] = 0;
            }
        }
    
        // 초기 번호 맵 생성 함수
        public static void initNumberMap(){
            sx = (n+1)/2 -1;
            sy = sx;
    
            beadMap[sx][sy] = 4; // 상어 표시
    
            int s = 1; // 방향 별 움직일 거리
            int[][] initDir = {{0,-1},{1,0},{0,1},{-1,0}};
    
            q = new LinkedList<>();
    
            q.offer(new int[]{sx,sy,0,0});
    
            while(!q.isEmpty()){
                int[] cur = q.poll();
    
                int x = cur[0];
                int y = cur[1];
                int d = cur[2]; // 현재 번호를 채울 방향
                int cnt = cur[3]; // 현재방향으로 몇번 움직였는지
    
                if(cnt == s){
                    if(d == 1 || d == 3){
                        s+=1;
                    }
                    d = (d + 1) % 4;
                    cnt = 0;
                }
                
                int nx = x + initDir[d][0];
                int ny = y + initDir[d][1];
    
                if(nx < 0 || nx >= n || ny < 0 || ny >= n){
                    continue;
                }
    
                numberMap.add(new int[] {nx,ny});
                q.offer(new int[] {nx,ny,d,cnt+1});
            }
        }
    }

     

    댓글