题意是让你构造一棵树使得这棵树的价值最大。树的价值等于节点价值的和,节点的价值等于度数i的函数f(i)。
首先n个点的树只需要总度数为2×n-2并且每个点的度数都为正那么这棵树肯定存在。
很容易想到的是用一个二维的DP去搞,DP[i][j]表示已经搞了i个点总共用j度的最大价值。但是这样要枚举三重循环复杂度太高了。
可以把每个点预先都放上1度,然后就变成n-2度的总度数最大价值是多少。注意放了1度以后函数会发生变化,现在的f(i)相当与之前的f(i+1),但是我们已经预先加了f(1),所以现在的f(i) = 之前的f(i+1)-之前的f(1)。
然后可以看成多重背包了。
#include <bits/stdc++.h>
using namespace std;
#define maxn 2111
const long long INF = 1e8;
long long dp[maxn];
long long f[maxn];
int n;
int main () {
//freopen ("in", "r", stdin);
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d", &n);
for (int i = 1; i < n; i++) {
scanf ("%lld", &f[i]);
}
long long ans = f[1]*n;
int gg = f[1];
for (int i = 0; i < n-1; i++) {
f[i] = f[i+1]-gg;
}
for (int i = 0; i <= n-2; i++) dp[i] = -INF;
dp[0] = 0;
for (int i = 1; i <= n-2; i++) { //枚举度数(最多n-2度) 相当于物品
for (int j = 0; j <= n-2; j++) { //枚举总度数 相当于背包容量
if (i+j <= n-2)
dp[j+i] = max (dp[j+i], dp[j]+f[i]);
}
}
printf ("%lld\n", ans+dp[n-2]);
}
return 0;
}