본문으로 바로가기
제품데스크톱 도구TASTECAD도면 확인TASTEFILES파일 관리TASTEFTP파일 전송TASTESSH원격 작업공간TASTEZIP압축과 해제개발 도구TASTECODERust 통합 개발 환경TASTESTUDIO통합 개발·테스트 환경TASTEETL데이터 통합(ETL)서버TASTEREMOTE원격 데스크톱 서버TASTEGEO공간정보 서버TASTEMAIL메일 작업공간시작하기다운로드문서구매모든 제품
마켓플레이스
소식
개발소식오늘의 개발 소식개발 문서프로그래밍 언어RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron알고리즘알고리즘 기초알고리즘 핵심알고리즘 심화실무 알고리즘
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스커뮤니티 안내
협업기술 전수홈페이지 구축데스크톱 앱 구축릴리스·결제 파이프라인판매 파트너문의
서비스원격 데스크톱설치 패키지 커스텀
TASTEDEV
제품

데스크톱 도구

TASTECAD복잡한 도면을 가볍게 열다TASTEFILES필요한 파일만, 가장 빠르게TASTEFTP파일이 오가는 가장 단정한 길TASTESSH서버와 나 사이, 더 단단한 연결TASTEZIP더 빠르게 묶고, 더 안전하게 풀다

개발 도구

TASTECODERust 앱을 편집 · 빌드 · 디버깅 · 테스트까지 한 창에서TASTESTUDIO편집부터 원격 테스트와 승인 기반 AI 수정까지TASTEETL값을 보며 데이터를 옮깁니다

서버

TASTEREMOTE우리 회사 서버로 운영하는 원격 데스크톱TASTEGEOGeoServer 호환 공간정보 서버를 Rust로 다시 세웁니다TASTEMAIL메일의 주도권을 다시 내 손에

시작하기

다운로드모든 제품 최신 판문서제품 사용법구매구독 · 영구 라이선스모든 제품모든 제품 한눈에
모든 제품
마켓플레이스소식
개발

소식

오늘의 개발 소식언어 · 프레임워크 · GitHub · AI 공식 발표개발 문서언어 · 프레임워크 · 알고리즘 안내서

프로그래밍 언어

RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart

프레임워크

프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular
서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express
앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron

알고리즘

알고리즘 기초복잡도 분석 · 정렬 · 탐색 · 기본 자료구조 · 트리와 힙알고리즘 핵심그래프 탐색 · 최단 경로와 최소 신장 트리 · 동적 계획법 · 탐욕 알고리즘 · 분할 정복 · 백트래킹알고리즘 심화문자열 알고리즘 · 수학과 정수론 · 비트 연산 · 구간 트리 · 유니온 파인드실무 알고리즘코딩 면접 풀이 전략 · LRU 캐시 · 레이트 리미터 · 일관된 해시
개발 문서 전체 보기
커뮤니티
프로젝트빌더와 작업 발견개발 로그결정과 시행착오프롬프트재사용 가능한 지시AI 도구 이슈Claude · Codex · Gemini 문제와 우회법쇼케이스완성된 결과커뮤니티 안내공개하고 함께 만드는 방식
협업
기술 전수Rust·egui 네이티브 앱 만들기홈페이지 구축10개 언어, 계정, 문서·다운로드데스크톱 앱 구축Rust·egui, WebView 없이릴리스·결제 파이프라인서명 · MSI·deb·rpm·AppImage · 해시판매 파트너소개하고 결제액의 30% 받기문의구축 · 제휴 · 투자 문의
서비스
원격 데스크톱브라우저로 내 컴퓨터에 접속설치 패키지 커스텀필요한 기능만, 설정은 미리
구매
KO
한국어EnglishDeutschEspañolFrançaisItalianoPortuguês (Brasil)日本語简体中文繁體中文
로그인
로그인
TASTEDEV

작은 도구부터, 더 좋은 개발까지.

support@tastedev.netTASTEDEV 후원하기
제품제품군구매문서다운로드마켓플레이스고객 지원
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스
정책개인정보처리방침이용약관구독 약관환불 정책커뮤니티 운영 정책
계정로그인가입하기
방문자
오늘
012345678901234567890123456789012345678901234567890123456789
어제
012345678901234567890123456789012345678901234567890123456789
누적 조회
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
상호
지엑스소프트
대표자
최영구
사업자등록번호
853-44-00368
주소
인천광역시 미추홀구 경인로 351 9층 V24
전화
+82-10-4404-1523
이메일
whitecalvin@tastedev.net
개인정보 보호책임자
최영구

© 2026 TASTEDEV제품 정보는 현재 검증된 개발 소스를 기준으로 합니다.출시·고도화 중

동적 계획법 문서
동적 계획법
개념동작 원리구현복잡도연습 문제실무 활용
토론

동적 계획법 안내서 · 5/6

연습 문제

아래 다섯 문제는 이 안내서를 위해 새로 만든 문제입니다. 풀이를 읽기 전에 먼저 상태, 점화식, 기저 사례, 계산 순서를 종이에 적고 코드로 옮겨 보세요. 모든 풀이는 Python 3.9 이상에서 실행됩니다.

문제 1: 부서진 칸이 있는 계단

계단이 n칸 있습니다. 0번 칸에서 시작해 한 번에 1, 2, 3칸씩 오를 수 있지만, 부서진 칸은 밟을 수 없습니다. n번 칸에 도착하는 방법의 수를 1_000_000_007로 나눈 나머지로 구하세요.

예: n = 4이고 2번 칸이 부서졌다면 0-1-4, 0-3-4, 0-1-3-4의 세 가지가 가능합니다. 0-2-4나 0-1-2-3-4는 2번 칸을 밟으므로 안 됩니다.

풀이: ways[i] = i번 칸에 서는 방법의 수. 부서진 칸은 0이고, 나머지는 ways[i] = ways[i-1] + ways[i-2] + ways[i-3]입니다. 기저 사례는 ways[0] = 1입니다.

MOD = 1_000_000_007


def count_climbs(n: int, broken: set[int]) -> int:
    ways = [0] * (n + 1)
    ways[0] = 1
    for i in range(1, n + 1):
        if i in broken:
            continue
        ways[i] = sum(ways[i - s] for s in (1, 2, 3) if i - s >= 0) % MOD
    return ways[n]


print(count_climbs(4, {2}))  # 3
print(count_climbs(30, set()))  # 53798080

문제 2: 격자를 건너는 가장 싼 경로

물류 창고 바닥이 통행료가 적힌 격자로 되어 있습니다. 로봇은 왼쪽 위 칸에서 출발해 오른쪽이나 아래로만 움직여 오른쪽 아래 칸에 도착해야 하며, 들어가는 모든 칸(첫 칸 포함)의 통행료를 냅니다. 최소 통행료 합을 구하세요.

풀이: cost[r][c] = (r, c) 칸에 도착하는 최소 비용. 각 칸은 위나 왼쪽에서만 들어오므로 cost[r][c] = grid[r][c] + min(위, 왼쪽)입니다. 각 행은 바로 위 행만 필요하므로 한 행만 들고 있으면 됩니다.

def cheapest_route(grid: list[list[int]]) -> int:
    cols = len(grid[0])
    row = [0] * cols
    for r, line in enumerate(grid):
        for c, toll in enumerate(line):
            if r == 0 and c == 0:
                row[c] = toll
            elif r == 0:
                row[c] = row[c - 1] + toll
            elif c == 0:
                row[c] = row[c] + toll
            else:
                row[c] = min(row[c], row[c - 1]) + toll
    return row[-1]


print(cheapest_route([[1, 3, 1], [1, 5, 1], [4, 2, 1]]))  # 7

문제 3: 오타 거리

검색창에서 사용자가 입력한 단어와 가장 가까운 상품 이름을 추천하려고 합니다. 두 단어 사이의 거리를, 한 단어를 다른 단어로 바꾸는 데 필요한 한 글자 삽입, 삭제, 교체의 최소 횟수(레벤슈타인 거리)로 정의하고 이를 계산하세요.

풀이: d[i][j] = s의 앞 i글자와 t의 앞 j글자 사이의 거리. 두 글자가 같으면 d[i][j] = d[i-1][j-1], 다르면 삭제(d[i-1][j]), 삽입(d[i][j-1]), 교체(d[i-1][j-1]) 중 최솟값에 1을 더합니다. 기저 사례는 d[i][0] = i, d[0][j] = j입니다.

def edit_distance(s: str, t: str) -> int:
    prev = list(range(len(t) + 1))
    for i, a in enumerate(s, start=1):
        cur = [i] + [0] * len(t)
        for j, b in enumerate(t, start=1):
            if a == b:
                cur[j] = prev[j - 1]
            else:
                cur[j] = 1 + min(prev[j], cur[j - 1], prev[j - 1])
        prev = cur
    return prev[-1]


print(edit_distance("keybaord", "keyboard"))  # 2
print(edit_distance("kitten", "sitting"))    # 3

문제 4: 상금 공정하게 나누기

한 팀이 정수 금액의 상금 여러 개를 받았습니다. 상금을 두 묶음으로 나누어 두 묶음의 합을 정확히 같게 만들 수 있을까요?

풀이: 합이 홀수면 불가능합니다. 짝수라면 합이 total // 2인 부분집합이 있는지 묻는 문제가 되고, 이는 참/거짓 값을 쓰는 0/1 배낭입니다. can[s]는 지금까지 본 상금으로 합 s를 만들 수 있으면 참입니다. 상금마다 한 번만 쓰도록 합을 큰 쪽에서 작은 쪽으로 돕니다.

def can_split_evenly(prizes: list[int]) -> bool:
    total = sum(prizes)
    if total % 2:
        return False
    target = total // 2
    can = [True] + [False] * target
    for p in prizes:
        for s in range(target, p - 1, -1):
            can[s] = can[s] or can[s - p]
    return can[target]


print(can_split_evenly([3, 1, 5, 9, 4]))  # False (합 22, 합 11인 부분집합 없음)
print(can_split_evenly([3, 1, 5, 9, 2]))  # True (9 + 1 = 3 + 5 + 2)

문제 5: 가장 긴 기온 상승 구간

날마다의 기온이 주어질 때, 고른 날마다 직전에 고른 날보다 기온이 엄격하게 높아지는 가장 긴 날짜 열(연속일 필요 없음)을 찾아 그중 하나를 돌려주세요.

풀이: O(n^2) LIS는 복원이 쉽습니다. length[i]는 i번째 날에서 끝나는 가장 긴 증가 부분 수열의 길이이고, parent[i]는 그 수열에서 바로 앞의 날을 기억합니다.

def warming_streak(temps: list[int]) -> list[int]:
    if not temps:
        return []
    n = len(temps)
    length = [1] * n
    parent = [-1] * n
    for i in range(n):
        for j in range(i):
            if temps[j] < temps[i] and length[j] + 1 > length[i]:
                length[i] = length[j] + 1
                parent[i] = j
    i = max(range(n), key=length.__getitem__)
    streak = []
    while i != -1:
        streak.append(temps[i])
        i = parent[i]
    return streak[::-1]


print(warming_streak([12, 9, 14, 10, 15, 11, 18, 13]))  # [12, 14, 15, 18]

입력이 길다면 복잡도 장의 bisect 버전에 위치 배열을 더해 O(n log n)으로 복원할 수 있습니다.

정리

  • 경우의 수 문제는 선택들을 더하고, 최적화 문제는 최솟값이나 최댓값을 고릅니다.
  • 격자와 문자열 문제는 두 인덱스를 쓰지만, 메모리는 한 행으로 충분한 경우가 많습니다.
  • "가능한가?"를 묻는 문제 상당수는 참/거짓 배낭으로 바뀝니다.
  • 크기뿐 아니라 해 자체를 출력해야 하면 부모 포인터를 저장합니다.
이 장에 대해 질문이 있나요?
이전 장복잡도다음 장실무 활용

댓글 0개

인기 댓글순최신순

로그인 · 로그인하면 댓글을 남길 수 있습니다.