출처 : https://www.acmicpc.net/problem/1261
알고스팟 성공
시간 제한 | 메모리 제한 | 제출 | 정답 | 맞은 사람 | 정답 비율 |
---|---|---|---|---|---|
2 초 | 128 MB | 6477 | 2469 | 1637 | 38.087% |
문제
알고스팟 운영진이 모두 미로에 갇혔다. 미로는 N*M 크기이며, 총 1*1크기의 방으로 이루어져 있다. 미로는 빈 방 또는 벽으로 이루어져 있고, 빈 방은 자유롭게 다닐 수 있지만, 벽은 부수지 않으면 이동할 수 없다.
알고스팟 운영진은 여러명이지만, 항상 모두 같은 방에 있어야 한다. 즉, 여러 명이 다른 방에 있을 수는 없다. 어떤 방에서 이동할 수 있는 방은 상하좌우로 인접한 빈 방이다. 즉, 현재 운영진이 (x, y)에 있을 때, 이동할 수 있는 방은 (x+1, y), (x, y+1), (x-1, y), (x, y-1) 이다. 단, 미로의 밖으로 이동 할 수는 없다.
벽은 평소에는 이동할 수 없지만, 알고스팟의 무기 AOJ를 이용해 벽을 부수어 버릴 수 있다. 벽을 부수면, 빈 방과 동일한 방으로 변한다.
만약 이 문제가 알고스팟에 있다면, 운영진들은 궁극의 무기 sudo를 이용해 벽을 한 번에 다 없애버릴 수 있지만, 안타깝게도 이 문제는 Baekjoon Online Judge에 수록되어 있기 때문에, sudo를 사용할 수 없다.
현재 (1, 1)에 있는 알고스팟 운영진이 (N, M)으로 이동하려면 벽을 최소 몇 개 부수어야 하는지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 미로의 크기를 나타내는 가로 크기 M, 세로 크기 N (1 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 미로의 상태를 나타내는 숫자 0과 1이 주어진다. 0은 빈 방을 의미하고, 1을 벽을 의미한다.
(1, 1)과 (N, M)은 항상 뚫려있다.
출력
첫째 줄에 알고스팟 운영진이 (N, M)으로 이동하기 위해 벽을 최소 몇 개 부수어야 하는지 출력한다.
예제 입력 1
3 3 011 111 110
예제 출력 1
3
예제 입력 2
4 2 0001 1000
예제 출력 2
0
예제 입력 3
6 6 001111 010000 001111 110001 011010 100010
예제 출력 3
2
힌트
이 문제는 알고스팟에서도 풀 수 있다.
풀이
N, M이 작기 때문에 dfs 를 사용했습니다.
부순 벽의 최소 개수를 현재 위치에 대하여 저장하고, 부순 벽의 최소 개수보다 크거나 같으면 dfs 함수를 return 합니다.
각 dfs 에서는 현재 위치의 4가지 사이드를 살펴보고 dfs 를 갱신합니다.
자세한 구현은 아래의 소스코드를 참조하시면 됩니다.
http://blog.naver.com/PostView.nhn?blogId=kks227&logNo=220447627125
다익스트라를 사용한 풀이는 위의 블로그를 참조하시면 됩니다.
소스코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <iostream> #include <vector> using namespace std; #pragma warning(disable:4996) #define SIDE_NUM 4 #define NM_MX 100 #define INF 987654321 int side[SIDE_NUM][2] = { { -1,0 },{ 0,1 },{ 1,0 },{ 0,-1 } }; int map[NM_MX][NM_MX] = { 0 }; int min_crash_map[NM_MX][NM_MX]; int is_visited[NM_MX][NM_MX] = { 0 }; int N, M; void dfs(int _depth, int _row, int _col, int _crashed_num) { // 현재 위치에서의 부서진 값의 최소가 있으면 해당 값을 사용한다. if (min_crash_map[_row][_col] <= _crashed_num) return; else min_crash_map[_row][_col] = _crashed_num; // 목적지 도착 if (_row == N - 1 && _col == M - 1) return; // 사이드 확인 for (int side_idx = 0; side_idx < SIDE_NUM; side_idx++) { int new_row = _row + side[side_idx][0]; int new_col = _col + side[side_idx][1]; if (new_row < 0 || new_row >= N) continue; if (new_col < 0 || new_col >= M) continue; if (is_visited[new_row][new_col]) continue; is_visited[new_row][new_col] = 1; dfs(_depth+1, new_row, new_col, _crashed_num + (map[new_row][new_col] ? 1 : 0) ); is_visited[new_row][new_col] = 0; } } int main() { scanf("%d %d", &M , &N); for (int r_idx = 0; r_idx < N; r_idx++){ for (int c_idx = 0; c_idx < M; c_idx++) { scanf("%1d", &map[r_idx][c_idx]); min_crash_map[r_idx][c_idx] = INF; } } is_visited[0][0] = 1; dfs(0, 0, 0, 0); cout << min_crash_map[N-1][M-1]; return 0; } | cs |