ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [BFS]-연습-불!
    알고리즘 스터디 01/숙제 2022. 12. 14. 12:03

    < BFS > - < 골드 4 >

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

     

    4179번: 불!

    입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다. 다음 입력으로 R줄동안 각각의 미로 행이 주어진다.  각각의 문

    www.acmicpc.net


    [ 4179 ] 불!

     

    지훈이는 미로에서 일을 한다. 지훈이를 미로에서 탈출하도록 도와주자!

    미로에서의 지훈이의 위치와 불이 붙은 위치를 감안해서 지훈이가 불에 타기전에 탈출할 수 있는지의 여부, 그리고 얼마나 빨리 탈출할 수 있는지를 결정해야한다.

    지훈이와 불은 매 분마다 한칸씩 수평또는 수직으로(비스듬하게 이동하지 않는다)  이동한다. 

    불은 각 지점에서 네 방향으로 확산된다. 

    지훈이는 미로의 가장자리에 접한 공간에서 탈출할 수 있다. 

    지훈이와 불은 벽이 있는 공간은 통과하지 못한다.

     

    :: 입력 ::

    입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다.

    다음 입력으로 R줄동안 각각의 미로 행이 주어진다.

     각각의 문자들은 다음을 뜻한다.

    • #: 벽
    • .: 지나갈 수 있는 공간
    • J: 지훈이의 미로에서의 초기위치 (지나갈 수 있는 공간)
    • F: 불이 난 공간

    J는 입력에서 하나만 주어진다.

    :: 출력 ::

    지훈이가 불이 도달하기 전에 미로를 탈출 할 수 없는 경우 IMPOSSIBLE 을 출력한다.

    지훈이가 미로를 탈출할 수 있는 경우에는 가장 빠른 탈출시간을 출력한다. 


     


    첫 제출에서는 조건문 안에
    visit != 0 
    이렇게 써서 틀렸다고 생각하고 그걸 고쳐서 다시 냈음
    솔직히 당연히 맞을 줄 알았는데 또 틀렸다고 해서 문제를 읽어보니까
    최소 시간을 출력하라고 나와있는데
    내가 짠 코드는 그냥 조건에 맞는 좌표가 나오면 그 시간을 바로 출력하게 해둠
    그래서 최솟값을 계산하는 코드를 넣어서 수정했는데 또 틀림
    그러고 정답코드를 봤음

    정답코드를 보고 알아낸 건
    BFS에서는 어차피 큐에 거리순으로 원소가 들어가게 되기때문에 따로 최소 시간을 구해줄 필요 없이 
    제일 먼저 조건을 만족하는게 최소 값이라는 거랑
    내가 조건문을 더럽게 못 쓴다는거임

    나는 거리를 저장하는 배열을 모두 0으로 세팅하고 입력 받는 도중에
    J(지훈이의 위치)나 F(불의 시작점)이 나오면 그 곳을 1로 바꾸고 해당 지점에서 BFS를 돌렸는데
    이 부분 조건문이 정답코드랑 달라서 내가 모르는 예외가 발생하는 것 같음

    + 나는 지훈이의 시작점이나 불의 시작점은 BFS에서 빼도 된다고 생각해서 그 부분을 continue로 넘어가게 해두었는데
    지금 생각해보니까 그러면 안되네 ,,
    까지 쓰고 테스트 해봤는데 조건을 바꿔도 맞음

    거리를 저장하는 배열에 대한 조건처리를 못한듯
    조건문을 쓸 때 감으로 하지말고 확실히 머릿속에 정리해두고 짜기 !

     

      코드  

    #include <iostream>
    #include <vector>
    #include <string>
    #include <queue>
    
    using namespace std;
    
    int board[1001][1001];
    int visit[1001][1001];
    int fire_visit[1001][1001];
    
    int main() {
    	int dir_x[] = { 0, 1, 0, -1 };
    	int dir_y[] = { 1, 0, -1, 0 };
    
    	int r, c;
    	cin >> r >> c;
    
    	string line;
    	queue<pair<int, int>> q;
    	queue<pair<int, int>> fire_q;
    
    	// 입력 받기
    	for (int i = 0; i < r; i++) {
    		cin >> line;
    		for (int j = 0; j < c; j++) {
    			if (line[j] == '#') board[i][j] = -1;
    			else if (line[j] == 'J') { board[i][j] = 1; q.push({ i, j }); visit[i][j]++; }
    			else if (line[j] == 'F') { board[i][j] = -1; fire_q.push({ i, j }); fire_visit[i][j]++; }
    		}
    	}
    
    	//for (int i = 0; i < r; i++) {
    	//	for (int j = 0; j < c; j++) {
    	//		cout << board[i][j];
    	//	}
    	//	cout << "\n";
    	//}
    
    	// 불 BFS 돌면서 fire_visit 배열에 각 칸까지 걸리는 시간 저장
    	while (!fire_q.empty()) {
    		int x = fire_q.front().first;
    		int y = fire_q.front().second;
    		fire_q.pop();
    
    		for (int i = 0; i < 4; i++) {
    			int nx = x + dir_x[i];
    			int ny = y + dir_y[i];
    
    			if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
    			if (fire_visit[nx][ny] != 0 || board[nx][ny] != 0) continue;
    
    			fire_visit[nx][ny] = fire_visit[x][y] + 1;
    			fire_q.push({ nx,ny });
    		}
    	}
    
    	/*for (int i = 0; i < r; i++) {
    		for (int j = 0; j < c; j++) {
    			cout << fire_visit[i][j];
    		}
    		cout << "\n";
    	}*/
    
    	// fire_visit에 저장된 불이 도달하는 시간과 지훈이의 걸음을 비교해서 시간 출력
    	// int time = r*c; << 최소 시간을 계산하기 위한 변수
    	// bool escape = false; << 탈출 가능여부를 저장
    	while (!q.empty()) {
    		int x = q.front().first;
    		int y = q.front().second;
    		q.pop();
    
    		for (int i = 0; i < 4; i++) {
    			int nx = x + dir_x[i];
    			int ny = y + dir_y[i];
    
    			if (nx < 0 || nx >= r || ny < 0 || ny >= c) 
    				// continue;
    			{
    				// nx와 ny가 해당 값에 도달했다는 것은 탈출에 성공했음을 의미 !
    				// x,y가 가장자리 일떄 nx,ny 값이 이 범위에 들어오니까
    				cout << visit[x][y];
    				return 0;
    			}
    			if (visit[nx][ny] != 0 || board[nx][ny] != 0) continue;
    
    			// visit[nx][ny] = visit[x][y] + 1;
    			if (visit[nx][ny] < fire_visit[nx][ny]) {
    				visit[nx][ny] = visit[x][y] + 1;
    				q.push({ nx,ny });
    				// if (nx == 0 || ny == 0 || nx == (r - 1) || ny == (c - 1)) {
    					// 이렇게 하면 최단시간이라는 조건을 만족하지 못함 ! 
    					// cout << visit[nx][ny];
    					// return 0;
    					// 어차피 큐에는 거리순으로 들어가기 떄문에 처음 고안했던대로 제일 먼저 조건을 만족하는 경우의 결과를 출력하는 게 맞음
    					// 정답코드와는 조건문을 사용하는 방식이 달랐음
    					// if (time > visit[nx][ny]) { time = visit[nx][ny]; escape = true; }
    				//}
    				/*else {
    					q.push({ nx,ny });
    				}*/
    			}
    		}
    
    	}
    
    	//for (int i = 0; i < r; i++) {
    	//	for (int j = 0; j < c; j++) {
    	//		cout << visit[i][j];
    	//	}
    	//	cout << "\n";
    	//}
    
    	//if (escape) cout << time;
    	//else cout << "IMPOSSIBLE";
    	cout << "IMPOSSIBLE";
    }

      최종 정답  코드  

    #include <iostream>
    #include <vector>
    #include <string>
    #include <queue>
    
    using namespace std;
    
    int board[1001][1001];
    int visit[1001][1001];
    int fire_visit[1001][1001];
    
    int main() {
    	int dir_x[] = { 0, 1, 0, -1 };
    	int dir_y[] = { 1, 0, -1, 0 };
    
    	int r, c;
    	cin >> r >> c;
    
    	string line;
    	
    	queue<pair<int, int>> q;
    	queue<pair<int, int>> fire_q;
    
    	// 거리를 저장할 배열을 -1로 초기화 해줌
    	for (int i = 0; i < r; i++) {
    		fill(fire_visit[i], fire_visit[i] + c, -1);
    		fill(visit[i], visit[i] + c, -1);
    	}
    
    	// 입력 받기
    	for (int i = 0; i < r; i++) {
    		cin >> line;
    		for (int j = 0; j < c; j++) {
    			if (line[j] == '#') board[i][j] = -1;
    			else if (line[j] == 'J') {
                // board[i][j] =1;
    				q.push({ i, j });
    				visit[i][j] = 0;
    			}
    			else if (line[j] == 'F') {
                // board[i][j] =1;
    				fire_q.push({ i, j });
    				fire_visit[i][j] = 0;
    			}
    		}
    	}
    
    	// 불 BFS 돌면서 fire_visit 배열에 각 칸까지 걸리는 시간 저장
    	while (!fire_q.empty()) {
    		int x = fire_q.front().first;
    		int y = fire_q.front().second;
    		fire_q.pop();
    
    		for (int i = 0; i < 4; i++) {
    			int nx = x + dir_x[i];
    			int ny = y + dir_y[i];
    
    			
                if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
                // board[nx][ny]가 -1 일 때랑 ( J와 F를 1로 처리한 후 ) 0이 아닐 때 모두 정답 
    			if (fire_visit[nx][ny] >= 0 || board[nx][ny] == -1 /* board[nx][ny] != 0 */) continue;
    
    			fire_visit[nx][ny] = fire_visit[x][y] + 1;
    			fire_q.push({ nx,ny });
    		}
    	}
    
    	// fire_visit에 저장된 불이 도달하는 시간과 지훈이의 걸음을 비교해서 시간 출력
    	while (!q.empty()) {
    		int x = q.front().first;
    		int y = q.front().second;
    		q.pop();
    
    		for (int i = 0; i < 4; i++) {
    			int nx = x + dir_x[i];
    			int ny = y + dir_y[i];
    
    			if (nx < 0 || nx >= r || ny < 0 || ny >= c)
    			{
    				// nx와 ny가 해당 값에 도달했다는 것은 탈출에 성공했음을 의미 !
    				// x,y가 가장자리 일떄 nx,ny 값이 이 범위에 들어오니까
    				cout << visit[x][y]+1;
    				return 0;
    			}
                // board[nx][ny]가 -1 일 때랑 ( J와 F를 1로 처리한 후 ) 0이 아닐 때 모두 정답 
    			if (visit[nx][ny] >= 0 || board[nx][ny] == -1 /* board[nx][ny] != 0 */) continue;
    			if (fire_visit[nx][ny] != -1 && fire_visit[nx][ny] <= visit[x][y]+1) continue;
    				
    			visit[nx][ny] = visit[x][y] + 1;
    			q.push({ nx,ny });
    		}
    	}
    
    	cout << "IMPOSSIBLE";
    }

     

    '알고리즘 스터디 01 > 숙제' 카테고리의 다른 글

    [BFS]-기본-유기농 배추  (0) 2023.02.14
    [BFS]-연습-숨바꼭질  (0) 2022.12.15
    [BFS]-연습-토마토  (0) 2022.12.06
    [BFS]-연습-미로 탐색  (0) 2022.11.25
    [BFS]-연습-그림  (0) 2022.11.25
준생e