$\newcommand{\O}{\mathrm{O}}$

各品物に個数の制約がついたナップサック問題のアルゴリズム. 少し意外だが, 個数制約なしの場合と同じ計算量で解くことができる.
本実装ではスライド最小値の考えを用いた実装をしている.
また各品物の個数を例えば $10$ コ → $1$ コ + $2$ コ + $4$ コ + $3$ コ のように $10$ 個以下の個数をすべて実現できるように
$2$ べきの重みを持つような品物に分解して 01 ナップザック問題に落とす方法もある. 計算量は $\O (nW \log M)$ ($M$ は品物の個数の最大値).
蟻本に詳しくのっているので参照してほしい.
時間計算量: $\O (nW)$ ($W$ は総重量の上限値)
template<typename T>
//価値v,重さw,個数m,重さの上限W
T knapsack(vector<T>& v,vector<int>& w,vector<int>& m, int W){
int n = (int)v.size();
vector<T> dp(W+1), deqv(W+1);
vector<int> deq(W+1);
for(int i = 0; i < n; i++){
for(int a = 0; a < w[i]; a++){
int s = 0,t = 0;
for(int j = 0; j*w[i]+a <= W; j++){
T val = dp[j*w[i]+a] - j*v[i];
while(s < t && deqv[t-1] <= val){
t--;
}
deq[t] = j;
deqv[t++] = val;
dp[j*w[i]+a] = deqv[s] + j*v[i];
if(deq[s] == j-m[i]){
s++;
}
}
}
}
return dp[W];
}