알고리즘 & 자료구조/그래프

[백준] 14502번 -연구소(JAVA)

윤도ri 2022. 6. 16. 18:28

문제를 간단히 정리했다.
벽 3개 세우고 바이러스 퍼뜨려서 0의 최대 갯수를 구하라!
1. 오,왼,상,하로 움직일 수 있으므로 방향값을 저장해놓고 사용하면 된다.  2. q에 2라는 값을 담아두고 그 주변 4방향으로 퍼뜨려나간다.
조건에 맞으면 q에 넣기! 퍼지고 있구나~
안전영역(0)의 갯수를 구해야하므로  0이면서 바이러스가 퍼뜨려지지 않은 영역(visited=false) 인 부분인 경우 count 를 올려준다.

| 입출력

BufferedReader 로 입력을 받고 System.out.println 으로 출력했다.

import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Lab_14502 {
    //1.벽을 3개 세운다. 
	//2.바이러스를 퍼뜨린다. 
	//3.최대 안전영역(0의갯수)를 구한다
	// --> 이 값을 max 값과 계속 비교하면서 최대값을 구한다. 
	
	public static int X; // X= M 
	public static int Y; // Y= N 
	public static int map[][];
	public static int max = 0;
	
	
	public static void main(String[] args) throws IOException{
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st = new StringTokenizer(br.readLine());
	
    Y = Integer.parseInt(st.nextToken());
    X = Integer.parseInt(st.nextToken());
    map = new int[X][Y];
    //0. map 을 (x,y)상태로 보기 위해서 X,Y 로 받아준다.
    
    //0.1 맨 윗줄이 y값이 Y-1 좌표부터 시작하므로 (높은것부터 점점 낮아져야 한다)
    for (int y = Y-1; y >=0; y--) {
    //0.2 왼쪽부터 x값을 받으니까 0부터 시작한다. 
    	st = new StringTokenizer(br.readLine());
		for (int x = 0; x < X; x++) {
			map[x][y]= Integer.parseInt(st.nextToken());
		} 
	}
    recursive(0);
    System.out.println(max);
	
	}
	//1. 벽을 3개 세운다 = 완전탐색 재귀 사용 
	
	public static void recursive(int index) {	
		if(index ==3) {
			//1.2 바이러스를 퍼뜨려 본다. == bfs 를 사용하라.  
			//1.3 남아있는 0의 갯수를 샌다. 
			int countOf0 = bfs();
			//1.4 남아있는 0의 갯수의 최댓값을 계속 갱신한다. 
			max = Math.max(max, countOf0);
			return;
		}
	//1.1 벽 3개를 만들어주고  위 if문에서 max값을 구한 다음 벽 부수고  새로운 경우의 수를 계속 탐색한다. 
		for (int i = 0; i < X; i++) {
			for (int j = 0; j < Y; j++) {
				if(map[i][j]==0) {
					map[i][j] = 1; //벽 만들기
					recursive(index+1);
					map[i][j] = 0; //벽 부수기 
					
				}
			}
		}
	}
	//2차원 에서 BFS 활용하기 위해 현재 좌표 기록하기. 
	public static int dx[] = new int[] {0,0,1,-1}; //상 하 오 왼
	public static int dy[] = new int[] {1,-1,0,0}; //상 하 오 왼 
	
	//2. 바이러스 퍼뜨리기
	public static int bfs() {
		
		Queue<int[]> q = new LinkedList<int[]>();
		
		boolean[][] visited = new boolean[X][Y];
		
		//2.1 바이러스가 2부터 뻗어나가므로 2를 q 에 넣어준다.
		for (int i = 0; i < X; i++) {
			for (int j = 0; j < Y; j++) {
				if(map[i][j]==2) {
					q.add(new int[] {i,j});
		//2.2  2를 들렸음을 check 해준다. 
					visited[i][j]= true;
				}
			}
		}
		//2.3  바이러스를 다 꺼내올때까지 반복한다. 
		while(!q.isEmpty()) {
			//q.poll -> 가장 먼저 보관한 값을 꺼내고 반환한다. 
			int list[] = q.poll(); 
			//2.4 현재 위치 등록 (curx = current x) 
			int curx = list[0];
			int cury = list[1];
			
			//2.5 다음위치로 퍼지는데 4방향이 가능하므로 4공간까지 반복문 돌린다.
			for (int i = 0; i < 4; i++) {
			//2.6 위치를 이동해준다. 
				int nx = curx + dx[i];
				int ny = cury + dy[i];
				//2.7
				//(1)현재 위치는 map 의 크기안에 들어가야 함 0 <= nx < X 
				                             //0 <= ny < Y
				//(2)방문했던 q는 제외해주어야 한다. --> visited = false
				//(3)벽(1)이 있는 공간도 제외해야 한다. --> map == 0
				// ** 이 조건에 충족하는 경우 바이러스가 퍼질 수 있다!
				
				if(0<=nx && nx< X && ny>=0 && ny < Y &&
						visited[nx][ny]==false && map[nx][ny]==0) {
					visited[nx][ny] = true; 
				//2.8 q에 넣었으므로 퍼진다. 
					q.add(new int[] {nx,ny}); 
					
				}
			}
		}
		//3.안전 영역의 갯수 구하기 
		int count = 0;
		for (int i = 0; i < X; i++) {
			for (int j = 0; j < Y; j++) {
				//3.1 0 이면서 바이러스가 들리지 않은 곳 = 안전영역
				if(map[i][j]==0 && visited[i][j]==false) {
					count++;
				}
			}
		}
		return count;
	}
    
}

 

  N과 M 을 받았는데 X와 Y는 무엇일까? 그리고 왜 Y부터 받는거지? 라고 충분히 생각할 수 있을 것 같다.  이건 문제를 헷갈리지 않게 풀기위해 X와 Y로 잡은 것이다. Map 의 경우 보통 위치를 (x,y) 로 나타내므로 X와 Y로 나타내고, 두번째로 

Y부터 받는 이유는 문제에서 N 은 곧 Y값이기 때문이다.

 

  또한 map 에 값을 담을때도 순서대로 탐색하면 X는 순서대로 증가하므로 x++,  Y는 가장 큰 수에서 -1 만큼 줄어들므로 y--  를 해주어야 한다는 점을 명심해야 한다.

 

 풀어본 사람들이 BFS 만 잘 이해하고 있으면 어렵지 않은 문제라고 한다. 나는 아직 부족한가보다 ^^,,, 언제나 질문은 환영하니 궁금한게 있으면 댓글 달아주세요 ^^! 

 

'알고리즘 & 자료구조 > 그래프' 카테고리의 다른 글

[백준] 3184번 - 양(JAVA)  (0) 2022.06.27