Problem Solving/Baekjoon Online Judge
[백준] 16197 두 동전
jujube bat
2020. 3. 8. 23:16
[문제이해]
1. N x M map에는 두 개의 동전(o) 벽(#)과 빈 칸(.)이 존재한다. (두 동전의 위치는 다름)
2. 두 동전을 동시에 움직일 수 있는 버튼이 있다. (방향은 상하좌우 4방향)
3. 두 동전 중 하나만 map에서 떨어뜨리기 위해 버튼을 최소 몇 번 눌러야하는지 구해야한다.
4. 단, 동전을 떨어뜨리거나 버튼을 10번보다 많이 눌러야 한다면, -1을 출력한다.
[설계]
1. x,y 구조체에 대한 구조체를 만들어 두 동전의 위치좌표를 간단하게 표현한다.
2. 4 방향의 버튼을 누르는 경우의 수를 재귀적으로 구현한다.
3. 재귀단계가 10이 넘어가면, 실패 (-1 출력)
4. 한 개의 동전만 떨어졌을때 버튼을 누른 횟수가 최소인지 체크하고, 최소이면 값을 갱신한다.
5. 두 동전이 모두 떨어지면, 실패 (해당 경우의 수 continue로 스킵)
6. 동전이 움직일 다음칸이 벽이라면 이동시키지 말아야한다.
7. 동전의 위치는 빈 칸이라고 생각한다. (문제에 동전이 있는 경우에도 이동한다고 명시, 입력받을때 동전 위치를 . 으로 처리)
8. 재귀적으로 경우의 수를 모두 살펴봤으면, 결과를 출력한다. ( res가 초기값인 1e9라면, 한 개의 동전을 떨어뜨리는 경우의 수가 없었던 것이므로 -1을 출력)
[회고]
- 동전이 있는 경우에도 이동할 수 있음을 간과했었다.
- 4차원 check 배열을 통해 이미 알아보았던 경우의 수일 경우 스킵을 하도록 구현 했는데, 굳이 그거까지 고려하지 않아도 됐음
[코드]
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef struct {
int x, y;
}pos;
char map[20][20];
int n, m;
int res = 1e9;
vector<pos> coin;
int dx[] = {-1,1,0,0}, dy[] = {0,0,-1,1};
void dfs(pos a, pos b, int cnt) {
if (cnt > 10) return;
for (int i = 0; i < 4; i ++) {
int nax = a.x + dx[i], nay = a.y + dy[i];
int nbx = b.x + dx[i], nby = b.y + dy[i];
bool a_flag = false, b_flag = false;
if (nax >= n || nax < 0 || nay >= m || nay < 0) a_flag = true; //a동전 떨어짐
if (nbx >= n || nbx < 0 || nby >= m || nby < 0) b_flag = true; //b동전 떨어짐
if (a_flag == !b_flag) {
res = min(res, cnt);
}
if (a_flag || b_flag) continue;
if (map[nax][nay] == '#' ) {
nax = a.x, nay = a.y;
}
if (map[nbx][nby] == '#' ) {
nbx = b.x, nby = b.y;
}
dfs({ nax,nay }, { nbx,nby }, cnt + 1);
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> map[i][j];
if (map[i][j] == 'o') {
coin.push_back({ i,j });
map[i][j] = '.';
}
}
}
dfs(coin[0], coin[1],1);
if (res == 1e9)
cout << -1;
else
cout << res;
return 0;
}
[출처]
본인