Partial Tree
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 823 Accepted Submission(s): 407
Problem Description
In mathematics, and more specifically in graph theory, a tree is an undirected graph in which any two nodes are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.
You find a partial tree on the way home. This tree has n nodes but lacks of n−1 edges. You want to complete this tree by adding n−1 edges. There must be exactly one path between any two nodes after adding. As you know, there are nn−2 ways to complete this tree, and you want to make the completed tree as cool as possible. The coolness of a tree is the sum of coolness of its nodes. The coolness of a node is f(d), where f is a predefined function and d is the degree of this node. What‘s the maximum coolness of the completed tree?
Input
The first line contains an integer T indicating the total number of test cases.
Each test case starts with an integer n in one line,
then one line with n−1 integers f(1),f(2),…,f(n−1).
1≤T≤2015
2≤n≤2015
0≤f(i)≤10000
There are at most 10 test cases with n>100.
Output
For each test case, please output the maximum coolness of the completed tree in one line.
Sample Input
2
3
2 1
4
5 1 4
Sample Output
5
19
题意:构造一颗最小生成树,但每个度数有个权值,使生成的权值最大。
题解:总共有2*n-2度数,如果从正面出发,就是直接完全背包,可能会使某些点被孤立,不能保证最小度数为1.所以先给每个点分配一个度数,直接n*f[1],因为最后肯定有度数大于1的点,先找出此度数和f[1]的差值(可负可正),相当于权值成了差值。最后还有n-2个度。这时候再用完全背包。即第一个for从2开始枚举到n-1度,(好比每个度数有无穷多个)第二个for枚举n-2个度。
状态转移方程: dp[j] = max(dp[j],dp[j-i+1]+f[i]). 为什么是j-i+1不是j-i呢,因为j是1到n-2中度,j-1相当于把那个1分配给一个度数已经为1的点,度数成了2,所以+f[2].
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 2020; const int inf = 0x3f3f3f3f; int f[maxn]; int dp[maxn]; int main() { int t; scanf("%d",&t); while(t--) { int n; int ans = 0; scanf("%d",&n); for(int i = 1; i<n; i++) scanf("%d",&f[i]); ans = n*f[1]; for(int i = n-1; i>1; i--) f[i] -= f[1]; for(int i = 1; i<=n-2; i++) dp[i] = -inf; dp[0] = 0; for(int i = 2; i <= n-1; i++) //因为1度已定,所以从2枚举度数 for(int j = 1; j <= n-2; j++) if(j>=i-1) dp[j] = max(dp[j],dp[j-i+1]+f[i]); printf("%d\n",ans+dp[n-2]); } return 0; }