하나의 큰 문제를 여러 개의 작은 문제로 나누어서 그 결과를 저장하여 다시 큰 문제를 해결할 때 사용하는 것
큰 문제를 작은 문제로 쪼개서 그 답을 저장해두고 재활용 -> 기억하며 풀기, 메모이제이션
예) 피보나치 수열
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 ...
이를 재귀로 구성하면 return f(n) = f(n-1) + f(n-2)

그러나 한 번 구한 작은 문제의 결과 값을 저장해두고 재사용 한다면 앞에서 계산된 값을 다시 반복할 필요가 없다. 즉, 매우 효율적으로 문제를 해결할 수 있고, 시간 복잡도가 O(n^2) → O(f(n)) 로 개선된다.
1. 겹치는 부분 문제
2. 최적 부분 구조

1) DP로 풀 수 있는지 확인
2) 문제의 변수 파악
3) 점화식 만들기
4) 메모하기(메모이제이션)
5) 가장 작은 문제 상태 알기
문제
분석
입력
출력
풀이
정리하면
처음 풀이
N, M = map(int, input().split())
A = {i: [] for i in range(1, N+1)}
for i in range(M):
a, b = map(int, input().split())
A[b].append(a)
B = [0 for i in range(N)]
# value가 빈 애들은 + 1
for i in A:
if A[i] == []:
B[i-1] += 1
for key, value in enumerate(A.items()):
#print(key, value)
if value[1] != []:
B[key] += (B[value[1][0]-1] + 1)
print(' '.join(map(str, B)))
안 봐도 시간 초과가 날 것 같았다...
근데 제출해보니 틀렸다
N, M = map(int, input().split())
A = {i: [] for i in range(1, N+1)}
for i in range(M):
a, b = map(int, input().split())
A[b].append(a)
B = [1] * N
# value가 빈 애들은 + 1
for i in A:
if A[i] == []:
B[i-1] += 1
for key, value in enumerate(A.items()):
if value:
a = 0
for i in value[1]:
a = max(a, B[i-1])
B[key] = a + 1
print(' '.join(map(str, B)))
얘는 시간 초과...
분석
입력
출력
풀이
지금 있는 칸의 거리를 구하려면 바로 윗 칸의 경로 수 + 바로 왼쪽 칸의 경로 수
웅덩이가 있는 경우는 0으로 처리
분석
입력
출력