[アルゴリズム]Java/SWEA/タイル/5556


[アルゴリズム]Java/SWEA/タイル/5556


質問する
質問リンク
方法
  • 繰り返しシーケンスは、n番目のビーズがどの列を攻撃するかを決定する
  • 各ビーズはi列を攻撃し、i列の一番上のレンガを見つけ、erase関数
  • を実行する.
  • erase関数レンガの数字をチェックし、数字の大きさの4つの方向範囲を探索し、レンガがあればerase関数を再帰的に呼び出す.
  • すべてのerase関数が終了した後、dropBrick関数を実行して地図の真ん中の空白を埋めます.
  • 以降に残ったレンガの数が最も少ない場合は、最高値が更新されます.
  • コード#コード#
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.StringTokenizer;
    
    public class Solution_5656_정현명 {
    	
    	static int deltas[][] = {{-1,0},{0,1},{1,0},{0,-1}};
    	static int map[][];
    	static int N,W,H;
    	static int numbers[];
    	static int minBrick;
    	static int[][] subMap;
    	public static void main(String[] args) throws IOException{
    		BufferedReader  br = new BufferedReader(new InputStreamReader(System.in));
    		int T = Integer.parseInt(br.readLine());
    		
    		StringTokenizer st = null;
    		StringBuilder sb = new StringBuilder();
    		for(int tc=1;tc<=T;tc++){
    			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 i=0;i<H;i++) {
    				st = new StringTokenizer(br.readLine());
    				for(int j=0;j<W;j++) {
    					map[i][j] = Integer.parseInt(st.nextToken());
    				}
    			}
    			
    			numbers = new int[N];
    			minBrick = Integer.MAX_VALUE;
    			permuRep(0);
    			
    			sb.append("#"+tc+" "+minBrick+"\n");
    		}
    		System.out.println(sb);
    	}
    	
    	// 중복순열로 n번째 구슬의 열 정하기
    	public static void permuRep(int cnt) {
    		
    		if(cnt == N) {
    			// 이미 벽돌이 다 깨져있으면 실행 x
    			if(minBrick!=0) attack(numbers.clone());
    			return;
    		}
    		
    		for(int i=0;i<W;i++) {
    			numbers[cnt] = i;
    			permuRep(cnt+1);
    		}
    	}
    	
    	// 벽돌 깨기 시작
    	public static void attack(int order[]) {
    		// 맵 복사
    		subMap = new int[H][W];
    		for(int i=0;i<H;i++) {
    			subMap[i] = map[i].clone();
    		}
    		// n번 구슬을 친다
    		for(int i=0;i<order.length;i++) {
    			int r = 0;
    			while(r<H) { // 제일 윗 행에서부터 처음으로 벽돌을 찾을때 까지 반복
    				if(subMap[r][order[i]] != 0) { // 가장 처음 벽돌을 찾으면 erase 실행
    					erase(r,order[i]);
    					break;				
    				}
    				r++;
    			}
    			dropBrick(); // 삭제되어 중간중간 비어있는 벽돌들을 아래로 떨어뜨림
    		}
    		
    		int cnt =0;
    	
    		for(int i=0;i<H;i++) {
    			for(int j=0;j<W;j++) {
    				if(subMap[i][j] != 0) cnt++;
    			}
    		}
    		
    		minBrick = minBrick > cnt ? cnt : minBrick;
    	}
    	
    	
    	public static void erase(int r, int c) {
    		int size = subMap[r][c]; // 벽돌 숫자
    		subMap[r][c] = 0; // 현재 벽돌을 제거
    		// 네 방향으로 
    		for(int i=0;i<4;i++) {
    			// 벽돌 숫자 크기만큼
    			for(int j=1;j<size;j++) {
    				int nextR = r + j*deltas[i][0];
    				int nextC = c + j*deltas[i][1];
    				
    				if(nextR>=0 && nextR < H && nextC >= 0 && nextC< W) {
    					if(subMap[nextR][nextC] != 0) { // 또 다른 벽돌을 만나면
    						erase(nextR,nextC); // erase 실행
    					}
    				}
    			}
    			
    		}
    	}
    	
    	
    	public static void dropBrick() {
    		for(int i=0;i<W;i++) { // 각 열에 대해
    			int idx = H-1; // 아래서부터 채워나갈 인덱스  
    			for(int j=H-1;j>=0;j--) {
    				if(subMap[j][i] != 0) { // 현재 탐색한 높이에 벽돌이 있다면
    					if(j == idx) { // idx와 현재 탐색한 높이가 같으면 패스
    						idx--;
    						continue;
    					}
    					// idx와 현재 탐색한 높이가 다르면 idx높이에 현재 벽돌을 옮기고, 벽돌을 제거
    					subMap[idx][i] = subMap[j][i];
    					subMap[j][i] = 0;
    					idx--;
    							
    				}
    			}
    		}
    	}
    
    }