-
[백준] 17244번 아맞다우산문제 풀이 2020. 4. 26. 21:44
17244 아맞다우산
문제
경재씨는 저녁 약속을 가기 전 챙기지 않은 물건들이 있는 지 확인하고 있다. 필요한 물건은 전부 챙긴 것 같았고 외출 후 돌아오는 길에 경재씨는 외쳤다.
"아 맞다 우산!!!"
경재 씨는 매번 외출하고 나서야 어떤 물건을 집에 놓고 왔다는 것을 떠올릴 때마다 자책감에 시달리는 것이 너무 싫었다.
외출이 잦은 경재 씨는 반복되는 일을 근절하기 위해 꼭 챙겨야 할 물건들을 정리해보았다. 하지만 지갑, 스마트폰, 우산, 차 키, 이어폰, 시계, 보조 배터리 등 종류와 개수가 너무 많았다.
평소 불필요한 움직임을 아주 싫어하는 경재 씨는 이 물건들을 최대한 빠르게 챙겨서 외출하는 이동 경로를 알고 싶었다.
경재 씨는 한 걸음에 상하좌우에 인접한 칸으로만 움직일 수 있다.
경재 씨를 위해 집을 위에서 바라본 모습과 챙겨야 할 물건들의 위치들을 알고 있을 때, 물건을 모두 챙겨서 외출하기까지 최소 몇 걸음이 필요한지 구하는 프로그램을 작성하자.
입력
첫 번째 줄에는 집의 가로 길이 N과 세로 길이 M이 입력된다. (3 ≤ N, M ≤ 50)
두 번째 줄부터는 집의 구조가 예제 입력과 같이 주어진다.
비어있는 곳은 '.'로 벽은 '#'로 입력된다. 경재 씨의 현재 위치는 S, 나가는 문의 위치는 E, 챙겨야 하는 물건은 종류에 상관없이 X로 입력된다.
챙겨야 하는 물건은 최대 5개까지 있을 수 있다. 집은 언제나 벽으로 둘러싸여 있고, 나가는 문은 언제나 하나이다.
출력
S에서 출발하여 모든 물건을 챙겨서 E까지 도착할 수 있는 최소 시간을 출력한다. 모든 물건을 챙길 수 없는 경우는 주어지지 않는다.
풀이)
bfs를 이용해서 푼 문제이다.
각 물건들의 위치를 저장해두고,
출발지 → 순서대로 물건들의 위치 → 도착지 순으로 방문해줬다.
예를 들어 물건이 A, B, C 3개가 있다면
출발지 → A → B → C → 도착지
bfs bfs bfs bfs 사이사이마다 bfs를 통해 시간구함.
A → C → B
B → A → C
B → C → A
C → A → B
C → B → A
이런 식으로 6가지 방법을 다 확인한 뒤
그 중 최소 시간을 가지는 방법의 시간을 출력해줬다.
*방문할 물건의 순서는 물건들의 인덱스들로 next_permutaion()을 통해 순열로 구해줬다.
코드)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108#include <stdio.h>#include <queue>#include <vector>#include <algorithm>using namespace std;#define INF 10000int n, m;int dy[4] = { -1,1,0,0 };int dx[4] = { 0,0,-1,1 };char map[50][50];bool visited[50][50];pair<int, int> s;pair<int, int> e;int result = 0;int bfs(pair<int,int> start,pair<int,int> end) {queue <pair<int, int>> qu;qu.push(start);visited[start.first][start.second] = true;int time = 0;int stop = 0;while (!qu.empty()){int size = qu.size();while (size-- && stop ==0){int y = qu.front().first;int x = qu.front().second;qu.pop();for (int i = 0; i < 4; i++) {int ny = y + dy[i];int nx = x + dx[i];if (ny >= 0 && ny < n && nx >= 0 && nx < m) {if (visited[ny][nx] == true || map[ny][nx] == '#')continue;if (ny == end.first && nx == end.second) {stop = 1;break;}visited[ny][nx] = true;qu.push({ ny,nx });}}}if (stop == 1)break;time++;}for (int i = 0; i < n; i++) {fill(visited[i], visited[i] + m, false);}if (stop == 1) {return time += 1;}return INF;}int main() {scanf("%d %d", &m, &n);getchar();int num = 0;vector <pair<int, int>> stuff;vector <int> vec; // 방문할 물건의 순서를 위한 vectorfor (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {scanf("%c", &map[i][j]);if (map[i][j] == 'S') s = { i,j };else if (map[i][j] == 'E') e = { i,j };else if (map[i][j] == 'X') {stuff.push_back({ i,j });vec.push_back(num);num++;}}getchar();}//만약 물건이 하나도 없다면if (num == 0) {printf("%d", bfs(s, e));return 0;}//물건이 하나라도 있다면int result = INF;do{int tmp = 0;//1. S에서 vec[0] 첫번째 물건까지의 시간tmp += bfs(s, stuff[vec[0]]);//2. 각 물건들끼리의 시간for (int i = 1; i < vec.size(); i++) {tmp += bfs(stuff[vec[i - 1]], stuff[vec[i]]);}//3.마지막 물건에서 E까지의 시간tmp += bfs(stuff[vec[num-1]], e);result = min(result, tmp);} while (next_permutation(vec.begin(),vec.end()));printf("%d",result);return 0;}cs '문제 풀이' 카테고리의 다른 글
[SWEA] 2817 부분수열의 합 (0) 2020.04.28 [SWEA] 1928 Base Decoder (0) 2020.04.27 [SWEA] 2805 농작물 수확하기 (0) 2020.04.23 [SWEA] 2806 N-Queen (0) 2020.04.23 [SWEA] 1954 달팽이 숫자 (0) 2020.04.22