HDU - 5534 H - Partial Tree解题报告

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 nn nodes but lacks of n−1n−1edges. You want to complete this tree by adding n−1n−1 edges. There must be exactly one path between any two nodes after adding. As you know, there are nn−2nn−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)f(d), where ff is a predefined function and dd is the degree of this node. What's the maximum coolness of the completed tree?

Input

The first line contains an integer TT indicating the total number of test cases. 
Each test case starts with an integer nn in one line, 
then one line with n−1n−1 integers f(1),f(2),…,f(n−1)f(1),f(2),…,f(n−1). 

1≤T≤20151≤T≤2015 
2≤n≤20152≤n≤2015 
0≤f(i)≤100000≤f(i)≤10000 
There are at most 1010 test cases with n>100n>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

题目大意:给你一棵树有N个节点,然后给出节点度数为d时的权值。

首先我们直接想到的就是总度数为2*(n - 1),要解决如何分配每个结点的度数 使得总cool值最大这个问题

然后可以猜想是不是只要每个结点的度数不为0,并且加和为2*(n - 1) 这样的树就会存在? 事实证明是正确的;

因为每个结点的度数不能为0,所以每个结点首先分配一个度数,然后问题转化为任意分配这n-2的度数,由于每个结点已经分配了一个度数,所以再分配的时候:假设再分配x度,那现在度数是x+1,权值为a[x+1], 原来权值a[0] ,所以要 ans += (a[x+1] - a[1]); 

为了方便处理,我们可以在输入的时候,从下标0开始输入,然后每个权值减去a[0] ,那问题就转化成背包问题了,n-2是背包容量,每个度数以及对应的权值分别是物品的占据的空间和价值,求容量为n-2时候的最大权值;

总共有2(n-1)个度,先给每一个点分配一个度(保证每个点有1个度),剩余n-2个度,还是分配给这n个点。 
问题转化为:空间为n-2的一个背包,如何分配给n个物品,使得价值最大 
问题再转化为:每个物品可以取0,1,2,3…..n-2个(对应每个点有多少度),即每个物品可取无限件,在一个空间为n-2的背包中,怎样取得最大价值 
问题最终转化为:一个完全背包问题 

--------------------- 
这句话引自别人的博客。

感觉这道题是一道十分好的题,现在缺的就是这种包含思维含量的DP题,所以一定要好好的理解。

下面给出AC代码:

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=50000+10;
const int INF=0x3f3f3f3f;
int dp[maxn];
int a[maxn];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(dp,-INF,sizeof(dp));
        memset(a,0,sizeof(a));
        int n;
        scanf("%d",&n);
        for(int i=0; i<n-1; i++)
        {
            scanf("%d",&a[i]);
            if(i) a[i]=a[i]-a[0];
        }

        int sum=a[0]*n;

        dp[0]=0;
        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]);
            }
        }

        sum+=dp[n-2];

        printf("%d\n",sum);
    }

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值