[문제]
https://www.acmicpc.net/problem/17069
[접근방법]
1. 처음에 완전탐색(BFS)으로 문제를 풀이하려고 했다...
2. 하지만 메모리 초과의 이유로 풀수 없는 문제라고한다..
3. 다이나믹프로그래밍을 써서 마지막 n-1,n-1 지점에 저장되어 있는 dp값이 정답!
4. 점화식을 구해 top-down이나 bottom-up 으로 쓰는 방법과는 다르게 3차원 배열을 이용하여 전에 기억하고 있는 값을 계속 더해(?) 나가는 방식으로 풀었다.
[문제풀이]
1. 큐에 넣어서 탐색하는 방법은 그대로 두고 거기에 dp의 요소를 적용시킴
2. 가로, 세로, 대각선의 경우를 다 따져봐야 하므로 dp[dir][nx][ny] 3차원 배열을 사용해야함
3. [dir] 공간을 만들어 주는 이유는 가로, 세로, 대각선으로 오는 경우가 다 다르기 때문이다. 만약 2차원 배열로 visited체크를 하게되면 가로로 A정점에 도착해서 A를 true로 만들어버리면 세로로 A정점으로는 다시는 들리지 못하기 때문이다. 각 경우가 다 다르게 계산이 되야하기 때문에 3차원을 쓰는것이다.
4.저 3차원 배열에 그 정점에 도달하는 방법의 수가 저장된다.
if (map[nx][ny] != 1 && map[nx - 1][ny] == 0 && map[nx][ny - 1] == 0 && map[nx][ny] == 0)
5. 위에서 [nx-1][ny] 와 [nx][ny-1] 를 하는 이유는 대각선이 움직일때는 움직인 B라는 정점의 좌,상이 벽이 아닌지를 판단해야 하기 때문이다.
참고 ) for(int i= 0; i < 3; i++)과 같은 for문은 상수개(3개)만큼 정해진 숫자 만큼돌기때문에 시간복잡도에 영향을 주지 않는다고 한다.
[전체 코드]
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int n;
struct Pos {
int x;
int y;
int dir;//가로(1),세로(2),대각선(3)인지 기억하기 위해
//int cnt;
};
int ddir[3][2] = { { 1, 0 }, { 0 , 1 }, { 1, 1 } };//가로, 세로로 이동할지 안할지의 여부(가로,세로,대각선)
int dx[] = { 0, 1, 1 };
int dy[] = { 1, 0, 1 };
long long int dp[3][32][32];
void bfs(int** map) {
for (int x = 0; x < n; x++) {
for (int y = 0; y < n; y++) {
for (int dir = 0; dir < 3; dir++) {
for (int i = 0; i < 2; i++) {
if (ddir[dir][i] == 1) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && ny >= 0 && nx < n && ny < n) {
if (map[nx][ny] != 1) {
dp[i][nx][ny] += dp[dir][x][y];
}
}
}
}
int nx = x + dx[2];
int ny = y + dy[2];
if (nx >= 0 && ny >= 0 && nx < n && ny < n) {
if (map[nx][ny] != 1 && map[nx - 1][ny] == 0 && map[nx][ny - 1] == 0 && map[nx][ny] == 0) {
dp[2][nx][ny] += dp[dir][x][y];
}
}
}
}
}
}
int main() {
cin >> n;
int** map = new int*[n];
memset(map, 0, sizeof(n));
for (int i = 0; i < n; i++) {
map[i] = new int[n];
memset(map[i], 0, sizeof(int) * n);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> map[i][j];
}
}
dp[0][0][1] = 1;//끝점 1로 초기화
bfs(map);
cout << dp[0][n-1][n-1] + dp[1][n - 1][n - 1] + dp[2][n - 1][n - 1] << endl;
return 0;
}
'📚 알고리즘 > DP(다이나믹 프로그래밍)' 카테고리의 다른 글
[백준 11727] 2×n 타일링 2_dp(c++) (0) | 2020.06.14 |
---|---|
[백준 2096] 내려가기_dp(c++) (0) | 2020.06.14 |
[백준 11057] 오르막수_dp(c++) (0) | 2020.05.31 |
[백준 11048] 이동하기(c++) (0) | 2020.05.24 |
[백준 1495] 기타리스트(c++) (0) | 2020.05.24 |