白駿17142号:研究所3






問題の説明

  • ウイルスは壁を通って上、下、左、右に移動できません.
  • Mウイルスのみがアクティブです.
  • アクティブなウイルスは、毎秒1グリッド拡散します.
  • すべての空間は、ウイルス(アクティブと非アクティブを区別しない)の時間を消費する必要があります.
  • 方法

    조합が実施され、
  • M個のアクティブウイルスが選択された.
  • ウイルスの拡散を発現するために,BFSを実現した.
  • は複数回の実験が必要なので、原版ではなくCopyBoardを使用しています.
  • CopyBoardは大量のメモリを消費します.アクセス処理スキームを追加すると、メモリがオーバーフローします.
  • Mの組合せでは、ウイルスを使用してすべての空間を充填する組合せと、そうすることができない組合せが混合される可能性がある.
  • は、ある組合せがすべての空間を満たさないからといって、すぐに−1に戻ることはできない.
  • -1は最も高い価格のMathです.min関数は、すべての譲受結果値を無視します.
  • pseudocode

    Main(){
    	M개의 바이러스를 실행하는 모든 조합 comb를 실행합니다.
        최종 시간을 계산합니다.    
    }
    comb(){
    	if(M개의 조합이 완성되면){
        	q에 M개의 pos조합을 넣습니다.
            입력값으로 만든 2차원 배열 Board를 복사한 CopyBoard를 만듭니다.
            CopyBoard와 q로 BFS를 수행합니다.
        }
    }
    BFS(q,board){
    	while(q에 값이 존재하지 않을 때까지){
        	while(현재의 q가 0이 될 때 까지){ // 같은 depth의 좌표들이 동시에 실행됩니다.
            	q의 값을 하나씩 꺼내어 4방탐색을 진행합니다.
                4방의 좌표 중 벽이 아니면서 아직 방문하지 않은 곳이면
                해당 좌표를 방문합니다.
            }
            현재 depth에서 모든 공간이 바이러스로 채워졌는지(0이 존재하지 않는지) 확인합니다. 
        }
        방문할 수 있는 모든 곳을 방문했는데도 0이 존재한다면 해당 조합으로는 모든 공간을 채우지 못하는 상황입니다.
    }
    
    ExistZero(board){
    	0이 존재하면 true, 그렇지 않으면 false를 반환합니다.
    }

    正解

    import java.util.*;
    
    public class Main {
    	static int N, M;
    	static int[] ans;
    	static List<pos> lst;
    	static int[] dx = { 0, 1, 0, -1 };
    	static int[] dy = { 1, 0, -1, 0 };
    	static int MinVal = Integer.MAX_VALUE;
    	static int[][] board;
    
    	public static void main(String[] args) {
    		Scanner sc = new Scanner(System.in);
    		N = sc.nextInt();
    		M = sc.nextInt();
    		ans = new int[M];
    		board = new int[N][N];
    		lst = new ArrayList<pos>();
    		for (int i = 0; i < N; i++) {
    			for (int j = 0; j < N; j++) {
    				int val = sc.nextInt();
    				if (val == 2) {
    					lst.add(new pos(i, j));
    					board[i][j] = 99; // 바이러스 위치
    				} else if (val == 1) {
    					board[i][j] = 999; // 벽 위치
    				} else {
    					board[i][j] = val;
    				}
    			}
    		}
    
    		comb(0, 0, board);
    		if (MinVal == 9998) {
    			System.out.println(-1);
    		} else if (!ExistZero(board)) {
    			System.out.println(0);
    		} else {
    			System.out.println(MinVal);
    		}
    
    	}
    
    	public static void comb(int depth, int start, int[][] board) {
    		if (depth == M) {
    			Queue<pos> q = new LinkedList<pos>();
    			for (int i = 0; i < M; i++) {
    				q.add(lst.get(ans[i]));
    			}
    			int[][] CopyBoard = new int[N][N];
    			for (int i = 0; i < N; i++) {
    				for (int j = 0; j < N; j++) {
    					CopyBoard[i][j] = new Integer(board[i][j]);
    				}
    			}
    
    			// CopyBoard에 Visited배열까지 사용해서 메모리 초과가 발생했었습니다.
    			MinVal = Math.min(MinVal, BFS(q, CopyBoard));
    
    			return;
    		}
    		for (int i = start; i < lst.size(); i++) {
    			ans[depth] = i;
    			comb(depth + 1, i + 1, board);
    		}
    
    	}
    
    	public static int BFS(Queue<pos> q, int[][] board) {
    		int cnt = 0;
    		while (!q.isEmpty()) {
    			int size = q.size();
    			cnt++;
    			while (--size >= 0) {
    				pos val = q.poll();
    				for (int d = 0; d < 4; d++) {
    					int nx = val.x + dx[d];
    					int ny = val.y + dy[d];
    					// 아직 방문하지 않은 길과 비활성 바이러스가 있는 곳을 지나갈 수 있습니다.
    					if (0 <= nx && nx < N && 0 <= ny && ny < N && (board[nx][ny] == 0 || board[nx][ny] == 99)) {
    						q.add(new pos(nx, ny));
    						board[nx][ny] = cnt;
    					}
    				}
    				if (!ExistZero(board)) {
    					return cnt;
    				}
    			}
    		}
    		// 모든 칸에 바이러스를 퍼뜨릴 수 없는 경우를 체크하기 위한 구간입니다.
    		// 곧바로 -1을 return하면 다른 경우의 수를 고려할 수 없습니다.
    		// ex) A,B,C를 선택했을 때 모든 칸에 바이러스를 퍼뜨리지 못했습니다. -> 만약 -1을 return하면
    		// 이후 B,C,D를 선택해서 5초만에 바이러스를 퍼뜨렸어도 -> Math.min(5,-1)이 되어 5초에 바이러스를 퍼뜨렸다는 결과를 얻지
    		// 못합니다.
    		if (ExistZero(board)) {
    			return 9998;
    		}
    		return 9999; // 실행되지 않는 코드입니다.
    	}
    
    	public static boolean ExistZero(int[][] board) { // 배열에 0이 존재하는지 확인합니다.
    		for (int i = 0; i < N; i++) {
    			for (int j = 0; j < N; j++) {
    				if (board[i][j] == 0)
    					return true;
    			}
    		}
    		return false;
    	}
    
    	static class pos {
    		int x;
    		int y;
    
    		public pos(int x, int y) {
    			super();
    			this.x = x;
    			this.y = y;
    		}
    
    		@Override
    		public String toString() {
    			return "pos [x=" + x + ", y=" + y + "]";
    		}
    
    	}
    }