happyso
study with happyso
happyso
전체 방문자
오늘
어제
  • 분류 전체보기 (302)
    • GIT (3)
    • 컴퓨터 기본 개념 (29)
    • 알고리즘 (125)
      • 알고리즘 문제 (115)
      • 알고리즘 개념 (10)
    • Go (2)
    • 클라우드 (54)
      • DevOps (4)
      • Kubernetes(쿠버네티스) (33)
      • AWS (6)
      • CKA (8)
    • 리눅스(Linux) (18)
      • 컨테이너(Container) (8)
    • Front (22)
      • JavaScript (2)
      • React (20)
    • Python (21)
      • Python 웹 크롤링 (11)
      • Django (7)
      • MachineLearning (3)
    • 데이터베이스 (6)
      • MariaDB (2)
      • MongoDB (4)
    • C언어 (5)
    • Trouble Shooting (2)
    • 네트워크 (8)
      • CCNA (5)
    • 보안 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • kubernetes
  • 15
  • edit
  • apply
  • replace
  • Patch
  • 18

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
happyso

study with happyso

[java, python] 백준 > DP > 다이나믹이 뭐예요?(14494)
알고리즘/알고리즘 문제

[java, python] 백준 > DP > 다이나믹이 뭐예요?(14494)

2021. 2. 26. 03:12

[문제]

안녕하세요~ 저는 오늘 다이나믹 프로그래밍(동적 계획법)을 설명하기 위해 등장한 욱제예요! 다이나믹은 이름이 엄청 거창하지만 사실 이름에 비해 개념은 간단하답니다. 다이나믹의 기본 아이디어는 바로 이전에 계산한 값을 사용해서 (= 이미 계산된 값을 사용해서, 어려운 말로 메모이제이션 한다고 해요) 반복되는 똑같은 연산 횟수를 줄이는 거예요.

예를 들어서, 5번째 피보나치 수열을 구하는 F(5)의 동작 과정을 살펴볼게요.

같은 함수가 불필요하게 많이 호출되는 것을 볼 수 있죠? F(2)와 F(3)을 미리 구해놓고 F(4)를 구할 땐 미리 구해둔 F(2)와 F(3)의 값을 이용하면 불필요한 호출을 줄일 수 있어요. 조금 엄밀하게 이야기 해볼게요. 수학적으로 피보나치 수열은 F(n) = F(n-1) + F(n-2)로 정의할 수 있죠? 이 식을 세우는 과정을 점화식을 세운다고 해요. 문제의 조건에 맞는 수식을 만들고 그 수식을 그대로 코드에 옮기면 아주 쉽게 다이나믹을 구현할 수 있어요.

물론 다차원 배열로도 가능해요! 오른쪽, 아래쪽으로만 움직일 수 있을 때, D[1][1]에서 D[x][y]까지 도달하는 경우의 수를 구하는 문제는 일일히 모든 경우를 다 계산할 필요 없이, D[i][j] = (i, j)에 도달하는 누적 경우의 수 = D[i-1][j] + D[i][j-1]를 세워서 해결할 수도 있죠.

어때요? 다이나믹 어렵지 않죠? 이제 문제를 풀어볼게요!

“→, ↓, ↘의 세 방향만 사용해서 한 번에 한 칸씩 이동할 때, 왼쪽 위 (1, 1)에서 출발하여 오른쪽 아래 (n, m)에 도착하는 경우의 수를 구하여라.”

시작!

입력

n과 m이 주어진다. (1 <= n, m <= 1,000)

출력

(1, 1)에서 (n, m)에 도달하는 경우의 수를 구하여라. 단, 경우의 수가 엄청 커질 수 있으므로 경우의 수를 1,000,000,007(=1e9+7)로 나눈 나머지를 출력한다.

 

 

www.acmicpc.net/problem/14494

 

14494번: 다이나믹이 뭐예요?

(1, 1)에서 (n, m)에 도달하는 경우의 수를 구하여라. 단, 경우의 수가 엄청 커질 수 있으므로 경우의 수를 1,000,000,007(=1e9+7)로 나눈 나머지를 출력한다.

www.acmicpc.net

[풀이-JAVA]

import java.util.Scanner;
public class Main{
    static long dp[][];
    public static long dp(int n, int m) {
        if (n==0||m==0) return 0;
        if (n==1&&m==1) return 1;
        if (dp[n][m]!=-1) return dp[n][m];
        long result = (dp(n, m-1) + dp(n-1, m) + dp(n-1, m-1))%1000000007;
        dp[n][m] = result;
        return result;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        dp = new long[n+1][m+1];
        for(int i=0; i<=n; i++){
            for(int j=0; j<=m; j++){
                dp[i][j] = -1;
            } 
        } 
        System.out.println(dp(n, m)%1000000007);
    }
}

[풀이-python => 런타임에러]

import sys
input = sys.stdin.readline
n, m = map(int, input().split())
d = [[-1]*(m+1) for _ in range(n+1)]
# n, m에서 왼쪽, 왼쪽위, 위 방향으로 이동하면서 1, 1에 도착 했을 때의 개수를 더한다.
def dp(n, m):
    if n==0 or m==0:
        return 0
    if n==1 and m==1:
        return 1
    if d[n][m]!=-1:
        return d[n][m]
    result = (dp(n,m-1)+dp(n-1,m)+dp(n-1,m-1))%1000000007
    d[n][m] = result
    return result
print(dp(n, m)%1000000007)
  • n,m의 위치에서 1,1 까지 가는 경우의 수를 구하기 위해 dp(n,m-1)+dp(n-1,m)+dp(n-1,m-1) 이런 식으로 재귀적으로 호출해준다.
  • n과 m이 둘다 1인 경우, 1,1 에서 1,1로 가는 거니까 방법은 하나기 때문에 1 리턴
  • n또는m중에 0을 가진 경우 여기서는 1,1부터 시작하기 때문에 0을 리턴(?) 해준다.
  • 구글에 나온 자바 코드를 보고 파이썬으로 바꿔서 해보았는데 런타임 오류가 났다.(내가 뭔가 잘못 써서 그런건지 아니면 python이라 그런건진 모르겠지만...이런 경우를 대비해 C++이나 JAVA로도 구현할 줄 알아야 할 것 같다.)

'알고리즘 > 알고리즘 문제' 카테고리의 다른 글

[python] 백준 > DP > 피보나치함수(1003)  (0) 2021.03.01
[python] 프로그래머스 > 힙 > 더 맵게  (0) 2021.02.27
[python] 백준 > 트리. 재귀 > 트리 순회(1991)  (0) 2021.02.26
[python] 프로그래머스 > 큐/스택 > 프린터  (0) 2021.02.25
[python] 프로그래머스 > DFS/BFS > 네트워크  (0) 2021.02.25
    '알고리즘/알고리즘 문제' 카테고리의 다른 글
    • [python] 백준 > DP > 피보나치함수(1003)
    • [python] 프로그래머스 > 힙 > 더 맵게
    • [python] 백준 > 트리. 재귀 > 트리 순회(1991)
    • [python] 프로그래머스 > 큐/스택 > 프린터
    happyso
    happyso

    티스토리툴바