对于选定若干种物品,然后要求从里面选出特定种物品,使得价值最大的问题。这种金明问题有两种:
类型1
一种是每个物品可以选1次,选了就没有了,此时令dp[i][j]表示可以选择前i种,并且选完之后恰好花费j元。此时dp[i][j]的划分为
d[i][j]={
方案1:恰好不买第i种,此时为dp[i-1][j]
方案2:就是要买第i种,并且第i种买且仅买1件,其余的钱买剩下的i-1种,并且要价值最大 即
dp[i-1][j-1*list[i].v]+list[i].v * list[i].w
}
类型2
每种物品可以任意选取多次,此时令dp[i][j]表示可以选择前i种,并且选完之后恰好花费j元。(也就是和前面定义相同)
此时dp[i][j]的划分为
dp[i][j]={
方案1:恰好不买第i种,此时为dp[i-1][j]
方案2:要买第i种,并且第i种至少买1件,其余的钱仍然可以买i种,并且价值最大 即
dp[i][j-1* list[i].v]+ list[i].v* list[i].w
}
此时代码会变成如下所示
int main() {
int dp[30001];
int N, m;
cin >> N >> m;
obj list[26];
for (int i = 1; i <= m; i++) {
cin >> list[i].v >> list[i].w;
}
dp[0] = 0;
memset(dp, 0, sizeof(dp));
int tempmax=0;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= m; j++) {
int index = i - list[j].v;
if (index>= 0) {
dp[i]= max(dp[index] + list[j].v*list[j].w, dp[i]);
}
}
}
cout << dp[N];
return 0;
}
其余的思考
对于动态规划的查表方法dp[i][j],可以发现,对于i和j在不同题目中会有不同的要注意的点,以本题为例
- 对于j,要注意到是恰好花完j元,因此正常来说要遍历第i行的元素的。
- 对于i,要注意到余下的钱是可以买i种还是可以买i-1种