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;
}

浙公网安备 33010602011771号