dp[i][j][0] = dp[i - 1][j - 1][0] + dp[i - 1][j - 1][1] + dp[i - 1][j - 1][2] ( for i > 1, j > 1 & (i, j) and (i - 1, j), (i, j - 1) is not a wall)
= 0 (Else cases)
dp[i][j][1] = dp[i - 1][j][0] + dp[i - 1][j][1] ( for i > 1, j >= 1 & (i, j) is not wall)
= 0 (Else cases)
dp[i][j][2] = dp[i][j - 1][0] + dp[i][j - 1][1] ( for i >= 1, j > 1 & (i, j) is not wall)
= 0 (Else cases)
추가적으로 벽인지 확인하는 함수를 따로 만들어서, index 범위를 넘어서거나 벽인 경우에 동일한 값을 출력하게끔하면
딱히 위 점화식처럼 케이스를 많이 찢지 않아도 된다.
전체 문제를 풀기 위해서 부분 문제로 찢어야 한다는 관점에서 개인적으로는 Top-down 방식이 더 직관적인 풀이 방법 같다.
해당 좌표에 들어오는 파이프의 방향이 중요하다는 것을 인식해주면 dp 인자를 3개 잡아야한다는 사실은 쉽게 관찰할 수 있을 것이다. DP문제에서 가장 중요한 지점은 최소한의 인자를 활용하여 점화식을 구현하는 것이다. 이 문제의 경우는 좌표 값 2개, 파이프의 방향 1개이므로 총 3개인 것이다.
Code
#include <bits/stdc++.h>
#define fastio ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
int state[33][33];
int n;
long long dp[33][33][3];
int state_value(int x, int y){
if(x < 1 || y < 1 || x > n || y > n) return 1;
else return state[x][y];
}
long long solve(int x, int y, int index){
if(x < 1 || y < 1 || x > n || y > n) return 0;
if(dp[x][y][index] != -1) return dp[x][y][index];
if(state_value(x, y)) return dp[x][y][index] = 0;
//First check (대각)
if(index == 0){
if(state_value(x - 1, y) == 0 && state_value(x, y - 1) == 0){
return dp[x][y][index] = solve(x - 1, y - 1, 0) + solve(x - 1, y - 1, 1) + solve(x - 1, y - 1, 2);
}
else return dp[x][y][index] = 0;
}
// Second check (vertical)
else if(index == 1){
return dp[x][y][index] = solve(x - 1, y, 0) + solve(x - 1, y, 1);
}
// Third check (horizontal)
else{
return dp[x][y][index] = solve(x, y - 1, 0) + solve(x, y - 1, 2);
}
}
int main(void){
fastio;
fill(&dp[0][0][0], &dp[32][33][3], -1);
cin >> n;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cin >> state[i][j];
}
}
dp[1][1][0] = 0;
dp[1][1][1] = 0;
dp[1][1][2] = 0;
dp[1][2][2] = 1;
cout << solve(n, n, 0) + solve(n , n, 1) + solve(n, n, 2) << "\n";
return 0;
}