728x90
개요
문제 링크
골드 4, DP
두 칸 이상 이동후 방향 전환을 하며 이동하는 경로의 수
접근
경로탐색 문제 중 생각할 여지를 많이 주는 좋은 문제이다. 2차원 dp를 사용하는데 두 가지 조건을 생각하면 되는 문제.
조건을 어기는 상황을 생각하자. 번개모양이 생기면 되는데, 이걸 dp로 어떻게 푸냐? 경로 탐색 dp의 근본부터 다시 생각해야 한다.
dp[y][x] = dp[y][x-1]+dp[y-1][x]
보통의 경로탐색 dp는 이렇다. 왼쪽과 아래쪽의 경로 수를 더해준다. 그런데 여기서는 이를 잘 응용해 이렇게 바꾸면 문제가 해결된다.
dp[y][x].from_left = dp[y][x-1].from_left + dp[y-1][x-1].from_down dp[y][x].from_down = dp[y-1][x].from_down + dp[y-1][x-1].from_left
무슨 말인가 하니, (y,x)의 경로의 수는 왼쪽과 아래쪽의 합이었다. 그럼 이를 다시 쪼개서, 왼쪽은 왼왼쪽 (LL)과 왼아 (LD)쪽의 합, 아래쪽은 아왼쪽 (DL)과 아아 (DD)쪽의 합이다. 우리가 피해야 할 부분은?
LDL에서 LD로 가는 경로와 DLD에서 DL으로 가는 경로이다. 좀 복잡할 수 있는데 천천히 생각해보면 번개모양이 그려짐을 알 수 있다.
그럼 L = LL+LD = LL+LDL+LDD, D = DL+DD = DLL+DLD+DD인데, 우리가 피할 부분은? LDL->LD, DLD->DL이므로 L = LL+LDD, D = DLL+DD를 해주면 된다.
즉 현재점의 왼쪽 origin = 왼쪽점의 왼쪽 origin, 왼아점의 아래 origin, 현재점의 아래 origin = 아래점의 아래 origin + 왼아점의 왼쪽 origin
Pseudo code
dp[y][x] = {
dp[y][x-1].left + dp[y-1][x-1].down,
dp[y-1][x].down + dp[y-1][x-1].left
}
answer = dp[y][x].left + dp[y][x].down
Source code
#include <iostream>
using namespace std;
#define D 100000
int main() {
int w, h;
cin >> w >> h;
int dp[h+1][w+1][2] = {};
dp[1][1][0] = 1;
dp[1][1][1] = 1;
for (int i=1; i<=h; i++)
for (int j=1; j<=w; j++) {
if (i==1&&j==1) continue;
dp[i][j][0] = (dp[i][j-1][0]+dp[i-1][j-1][1])%D;
dp[i][j][1] = (dp[i-1][j][1]+dp[i-1][j-1][0])%D;
}
cout << (dp[h][w][0]+dp[h][w][1])%D;
}
728x90
'백준브실골 > DP' 카테고리의 다른 글
백준 24466, 도피 (0) | 2023.03.28 |
---|---|
백준 10109, Troyangles (0) | 2023.03.28 |
백준 10978, 기숙사 재배정 (0) | 2023.02.19 |
백준 13707, 합분해 2 (0) | 2023.02.17 |
백준 22968, 균형 (2) | 2023.02.17 |
백준 17856, Just Passing Through (0) | 2023.02.17 |
백준 1663, XYZ 문자열 (0) | 2023.02.17 |
백준 13910, 개업 (0) | 2023.02.17 |
댓글