题目链接
一道思维爆炸的题,过的有诸多不易,还好没去赛场,不然得凉,这道题想了还真挺久的。
这道题就是问你如何用可以这么(N-1个)节点构成一棵完整的树,每个节点的可以连出去的边分别为(1,2,3,......,N-1),并且还要使得这棵树的价值最大,求该最大价值。
挺复杂的,也是在大佬教学下才逐渐明白整个思路的,我们有N个点,用它们建树的话会有N-1条边,就意味着有2*(N-1)的度,那么,我们既要满足最后选取的节点数为N,也要使得最后的度恰为2*(N-1)==2*N-2,好麻烦!!!但是,我们得到的条件确实两个,我们可以利用边与度的关系,我们即要建N条边,那么,我们先投N个1号节点(只有一条边)进去,那么此时度就是N,换而言之,我们剩下就是为了补全N-2个度就可以了,怎么补?我们可以利用与一号节点的差值来补,相当于剔除一个一号节点,再补一个更大的节点进来,然后价值就是原价值与一号节点的差值然后就是道典型的完全背包了,使得最后满足条件即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN=2020;
int N, a[maxN];
ll dp[maxN]={0};
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &N);
for(int i=1; i<N; i++) { scanf("%d", &a[i]); dp[i]=-INF; }
dp[0]=N*a[1];
for(int i=2; i<N; i++) a[i]-=a[1];
for(int i=1; i<=N-1; i++) dp[i]=i*a[1];
for(int i=1; i<N-1; i++)
{
for(int j=i; j<=N-2; j++)
{
dp[j] = max(dp[j], dp[j-i]+a[i+1]);
}
}
printf("%lld\n", dp[N-2]);
}
return 0;
}