题意
要构建一棵n个点的树,树的权值为所有结点的权值和,每个结点的权值为(f(d)),d为结点的度数。
分析
n个结点的树,n-1条边,即度数和为2n-2。每个结点的度数至少为1,所以先令每个结点的度数为1。剩下n-2的的度数再分配掉,将这个过程转化为完全背包,每个度数可以出现的次数不限。dp[i][j] 表示在前i个度数中选择度数和为j的情况的最优值。(dp[1][0]= n*f[1]),表示已经将所有点初始化为度数为1。
状态转移方程:(dp[i][j] = max(dp[i-1][j],dp[i][j-i+1]+f[i]-f[1]))。
因为之和前一维有关,可以省去第一个维度。
#include<bits/stdc++.h>
using namespace std;
#define eps 1e-7
const int maxn = 1e5+5;
typedef long long LL;
int dp[maxn];
int v[maxn];
const int INF = 0x3f3f3f3f;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T; scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
for(int i=1;i<n;++i){
scanf("%d",&v[i]);
}
memset(dp,-INF,sizeof(dp));
dp[0] = n*v[1];
for(int i=2;i<n;++i){
for(int j=0;j+i-1<=n-2;++j){
dp[j+i-1] = max(dp[j+i-1], dp[j]+v[i]-v[1]);
}
}
printf("%d
",dp[n-2]);
}
return 0;
}