P1064 [NOIP 2006 提高组] 金明的预算方案

链接

https://www.luogu.com.cn/problem/P1064

题目

思路

刚开始想复杂了:想象多棵树的dp。但是实际上由于最多只有两个子节点,所以可以直接用分组dp:把每棵树变成1/2/4的“合体”选择版。 比如如果只有一个主元件,那么就添加一个物品。如果有一个主元件加上一个附元件,那么加入两个。然后对新的条件使用分组dp。

代码

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
#define int long long
const int N = 100;
const int M = 3300;
int val[N], vit[N], up[N];
int dp[N][M];
vector<int> bag[N], value[N];
vector<int>vt[N];
signed main()
{
	IOS;
	int m, n; cin >> m >> n;
	m /= 10;
	for (int i = 1; i <= n; i++)
	{
		cin >> val[i] >> vit[i] >> up[i];
		val[i] /= 10;
		if (up[i])vt[up[i]].push_back(i);
	}
	int cnt = 0;
	for (int i = 1; i <= n; i++)
	{
		cnt++;//这个cnt其实可以省为i,就是后面都不需要
		if (up[i] == 0)
		{
			bag[cnt].push_back(val[i]), value[cnt].push_back(val[i] * vit[i]);//分组,必有的一个
			if (vt[i].size() == 1)//只有一个附元件
			{
				bag[cnt].push_back(val[i] + val[vt[i][0]]),
					value[cnt].push_back(val[i] * vit[i] + val[vt[i][0]] * vit[vt[i][0]]);
			}
			else if (vt[i].size() == 2)//两个附元件
			{
				for(int j : vt[i])bag[cnt].push_back(val[i] + val[j]),
					value[cnt].push_back(val[i] * vit[i] + val[j] * vit[j]);
				bag[cnt].push_back(val[i] + val[vt[i][0]] + val[vt[i][1]]),
					value[cnt].push_back(val[i] * vit[i] + val[vt[i][0]] * vit[vt[i][0]] + val[vt[i][1]] * vit[vt[i][1]]);
			}
		}
	}
    //bag就是新的代价,value就是新的价值
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			if (value[i].size())
				for (int k = 0; k < value[i].size(); k++)
				{
					if (j >= bag[i][k])dp[i][j] = max(dp[i - 1][j], max(dp[i][j], dp[i - 1][j - bag[i][k]] + value[i][k]));//这里的max要注意不能漏
					else dp[i][j] = max(dp[i - 1][j], dp[i][j]);
				}
			else dp[i][j] = dp[i - 1][j];
		}
	}
	cout << dp[cnt][m] * 10;

	return 0;
}
posted @ 2025-02-14 16:31  WHUStar  阅读(58)  评论(0)    收藏  举报