Knapsack 알고리즘

2024. 9. 15. 17:36·Algorithm/Basics

여러 제한 사항들에 따라 문제 유형을 분류해 보았다. 풀면서 익혀보자.

 

1. 가방문제 (최대, 보석 제한X)

 

먼저 이러한 dp 테이블을 두자. (0으로 초기화)

i번째 칸이 의미하는것은 가방에 i(kg)까지 담을 수 있을 때 최대 가치이다.

 

그러면 5kg짜리 보석만 있다고 생각하자. dp[5]부터 채우면 다음과 같다.

i번째 칸에 5kg을 담는다고 가정했으니까 인덱스는 5빼주고 그 dp[i-5]에서 v(12)의 가치를 더해준다. 

마찬가지로 이번에 3kg짜리 보석도 함께 있다고 생각해보자

dp[i]=max(dp[i],dp[i-w]+v) 로 점화식을 세울 수 있겠다.

예를 들어 dp[6]의 경우에는 기존의 dp[6](=12)보다 dp[6-3]+8(=16)이 더 크므로 바꿔준다.

 

이런식으로 나머지 6,4도 적용해 최종적으로 dp[11]을 구하면 된다. 

 

코드 

n,m=map(int,input().split())

dp=[0 for _ in range(m+1)]
for i in range(n):
	w,v=map(int,input().split())
	for j in range(w,m+1):
		dp[j]=max(dp[j],dp[j-w]+v)
    
print(dp[m])

 

2. 동전 교환(최소, 동전 제한X)

 

마찬가지로 dp테이블을 둔다. 이 때 최소 동전의 갯수를 구하므로 최대값으로 초기화시켜준다.

dp[i]가 의미하는것은 i원을 거슬러주는데 사용된 동전의 최소 갯수이다. 

만약 1원짜리로만 돈을 거슬러준다하면 

2원까지 함께 사용한다면

점화식은 dp[i]=min(dp[i-coin[j]]+1,dp[i])

최종 5원까지 사용했을때

 

코드

n=int(input())
coin=list(map(int,input().split()))
m=int(input())
dp=[1000 for _ in range(m+1)]
dp[0]=0
for i in range(n):
	for j in range(coin[i],m+1):
		dp[j]=min(dp[j],dp[j-coin[i]]+1)
    
print(dp[m])

 

3. 최대 점수 구하기 (한 유형당 한개만!)

 

앞에 문제하고 차이가 있다면 문제를 여러번 풀 수 있는것이 아닌 한번만 풀 수 있다는 것이다.

그러다보니 앞에 어떤 선택을 했냐에 따라 뒤에 선택값이 달라질 수 있으므로 

2차원 dp 배열을 두자

dp[i][j] 테이블의 의미는 i번째 문제까지 적용했을때  나한테 j분의 시간이 주어졌다면 얻을 수 있는 최대 점수이다. 

1번째칸에서 5분부터 시작해 10을 채워나간다. 

이때 우리가 따라서 참조해야할것은 그 전칸(왼쪽칸)이 아닌 dp[i-1][j-pt]번째 행이다. (dp[1][10]은 20이 아닌 10이다. 중복 X이므로)

따라서 dp[1][10]은 dp[i][j]=dp[i-1][j-t]+v이다.

 

2번째 행을 시작하기 전에 그전에 적용된 것을 복사한다. 

dp[2][12] 부터 시작한다하면 dp[1][0]에서 25를 더한다.

이때 25가 10보다 크므로 dp[2][12]는 25로 채워준다. dp[2][17]같은 경우에는 dp[1][5]에서 25를 더하므로

35가 된다. (dp[2]는 2번 문제까지 적용된)

3행도 마찬가지로 2행 것을 복사한 다음에 똑같이 해주면 다음과 같이 채워진다.

그렇게 해서 최종적으로 dp[5][20]을 구하면 된다.

이렇게 2차원으로 해도 되지만 메모리 낭비가 심하다... 1차원으로 해결하는 방법도 있다.

여기서 dp[i]는 i분이 주어졌을 때 얻을 수 있는 최대 점수

이번에는 뒤에서부터 값을 매긴다. dp[20]은 dp[15]에서 10을 더한 값

즉 dp[i-t]+v=dp[i]

2번째 행도 마찬가지로 dp[20]에서 t를 뺀 행인 dp[12]에서 25를 더하는 식으로

3번째 행도 마찬가지로 dp[20]에서 8을 뺀 dp[12]에서 15를 더하면 dp[20]은 40이 된다. 

앞의 값을 참조하고 뒤에 값을 안보기 때문에 중복될 여부가 없다. 

n,m=map(int,input().split())
dp=[0 for _ in range(m+1)]
for i in range(n):
	ps,pt=map(int,input().split())
	for j in range(m,pt-1,-1):
		dp[j]=max(dp[j],dp[j-pt]+ps)
 
print(dp[m])

 

4. 그 외의 백준 문제들..

https://www.acmicpc.net/problem/9084

풀이: https://didu-story.tistory.com/440

 

[백준] (Python) 2293번 - 동전1 (골드5, dp)

기업 코딩테스트 연습을 위해 python으로 문제풀이 하였습니다. 😅 ⚫️ 문제 https://www.acmicpc.net/problem/2293 2293번: 동전 1 첫째 줄에 n, k가 주어진다. (1 ≤ n ≤ 100, 1 ≤ k ≤ 10,000) 다음 n개의 줄에는

didu-story.tistory.com

 

출처: it 취업을 위한 알고리즘 문제풀이 입문 (with C/C++)

'Algorithm > Basics' 카테고리의 다른 글

Floyd-Warshall 알고리즘  (0) 2025.12.26
Bellman-Ford 알고리즘  (0) 2025.12.19
Dijkstra 알고리즘  (0) 2025.12.17
Minimum Spanning Tree 알고리즘  (0) 2025.12.16
Union-Find 알고리즘  (0) 2025.12.16
'Algorithm/Basics' 카테고리의 다른 글
  • Bellman-Ford 알고리즘
  • Dijkstra 알고리즘
  • Minimum Spanning Tree 알고리즘
  • Union-Find 알고리즘
dev.di
dev.di
devdi 님의 블로그 입니다.
  • dev.di
    개발 블로그
    dev.di
  • 전체
    오늘
    어제
    • 분류 전체보기 (28)
      • Algorithm (9)
        • Basics (9)
      • AWS (0)
        • AWS (0)
        • SAA (0)
      • Computer Science (1)
        • OS 벼락치기 (1)
        • DB 벼락치기 (0)
      • Data Engineer (8)
        • Airflow (0)
        • Data Warehouse (0)
        • Kafka (0)
        • Spark (0)
        • 데브코스 (8)
      • Docker (0)
      • Interviews (1)
      • Network (2)
        • Physical Layer (0)
        • Data Link Layer (0)
      • OOP (3)
        • GoF (3)
      • Python (4)
        • Django (3)
        • Scraping (1)
      • Software Engineering (0)
      • Spring (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    포트포워딩
    IPv4
    sql
    데이터 웨어하우스
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
dev.di
Knapsack 알고리즘
상단으로

티스토리툴바