题解 | #[NOIP2006]金明的预算方案#

[NOIP2006]金明的预算方案

https://ac.nowcoder.com/acm/problem/16671

我来提供一下我自己想出来的思路
我这个思路的优点是,当附件有很多很多个的时候,你不用去把每种情况都穷举出来
首先,我定义了两个二维数组,二维数组itemv和二维数组itemw,itemv和itemw当中的每一个数组的第一个元素是主件,其余的为附件
然后我的dp也是二维数组,第一个i代表前i个物体,第二个j代表的是价格的下标
然后关键来了,我强行把第一个主件给它加上去,然后剩余附件使用选择性的加上去,然后这样主件和他的附件过完一轮之后,与上一个主件附件进行比较大小,如果这次主件附件加上去比它大,那就保留,否则就回到上一次的进度。

#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> itemv;//这个二维数组中的每一个数组的第一个元素是主件的价格,其余的为附件的价格
vector<vector<int>> itemw;//这个二维数组中的每一个数组的第一个元素是主件的重要程度,其余的为附件的重要程度
int dp[70][33000];//第一个i代表前i个物体,第二个j代表的是价格的下标
int id[10000];
void solve() {
	vector<int> temp(100, 0);
	itemv.push_back(temp);
	itemw.push_back(temp);
	int n, m;
	cin >> n >> m;
	for (int i = 1;i <= m;i++) {
		int v, p, q;
		cin >> v >> p >> q;
		if (q <= 0) {
			itemv.push_back(vector<int>(1, v));
			itemw.push_back(vector<int>(1, p));
			id[i] = id[i - 1] + 1;
		}
		else {
			itemv[id[q]].push_back(v);
			itemw[id[q]].push_back(p);
			id[i] = id[i - 1];//因为它输入的q是主件的行数,所以需要一个id数组来转换一下
		}
	}
	for (int i = 1;i < itemv.size();i++) {
		for (int j = 0;j < itemv[i].size();j++) {
				if (j == 0) {				//如果是主件
					for (int k = n;k >= itemv[i][0];k--) {
						dp[i][k] = dp[i - 1][k - itemv[i][j]] + itemv[i][j] * itemw[i][j];	//强行把当前这个主件给加上去
					}
				}
				else {					    //如果是附件
					for (int k = n;k >= itemv[i][0] + itemv[i][j];k--) {		//这里itemv[i][0] + itemv[i][j]就是主件和当前所对应的附件的价格相加后的值
						dp[i][k] = max(dp[i][k], dp[i][k - itemv[i][j]] + itemv[i][j] * itemw[i][j]);
					}
				}
		}
		for (int k = 0;k <= n;k++) {		
			dp[i][k] = max(dp[i][k], dp[i - 1][k]);		//在价格为k时,如果加完之后还没有上一轮加得多,那么就返回上一轮的进度
		}
	}
	cout << dp[itemv.size() - 1][n] << endl;
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	solve();
	return 0;
}
全部评论

相关推荐

微风不断:兄弟,你把四旋翼都做出来了那个挺难的吧
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务