洛谷动态规划训练总结:开心的金明 系列

对于选定若干种物品,然后要求从里面选出特定种物品,使得价值最大的问题。这种金明问题有两种:

类型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在不同题目中会有不同的要注意的点,以本题为例

  1. 对于j,要注意到是恰好花完j元,因此正常来说要遍历第i行的元素的。
  2. 对于i,要注意到余下的钱是可以买i种还是可以买i-1种

你可能感兴趣的:(洛谷训练)