HDU 5534 Partial Tree 【完全背包+思维】

本文探讨了一道经典的图论问题——如何通过连接特定数量的边来构建一棵生成树,使得树中各节点的“酷值”之和最大化。文章详细解析了问题背后的数学原理,并提出了一种基于完全背包问题的优化解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Partial Tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit:262144/262144 K (Java/Others)
Total Submission(s): 1480    Accepted Submission(s): 743

Problem Description

Inmathematics, and more specifically in graph theory, a tree is an undirectedgraph 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 lacksof n−1 edges. You wantto 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 tocomplete this tree, and you want to make the completed tree as cool aspossible. The coolness of a tree is the sum of coolness of its nodes. Thecoolness of a node is f(d), where f is a predefinedfunction and d isthe 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 testcases.
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 testcases with
n>100.

 

 

Output

For each test case, please output the maximum coolness of the completed tree in oneline.

 

 

Sample Input

2

3

2 1

4

5 1 4

 

 

Sample Output

5

19

 

【题意】


给出n,现在需要你连(n-1)条边使之构成一棵生成树,并给出一个函数f(d)表示度数为d的点的价值,问构造后所有点价值总和的最大值。


【思路】


先给出一个结论,n个节点的生成树所有点的度数总和为2*(n-2)。


那现在我们要做的便是把这2*(n-2)个度数分给n个点,求价值和最大值。


很容易联想到完全背包,可以这样转化:现在有(n-1)个物品,每个物品有一个重量和价值,现在需要你从中选出正好n件物品(可以重复选),且重量和正好为2*(n-1),求物品价值和最大值。


但这样去做由于还要加上一层关于物品件数的循环,复杂度就比较高了。我们需要考虑优化。


我们可以将每个节点先分配一个度,然后剩下(n-2)个度就可以随意分配,而没有个数限制了。


这样的话,就转化成了一个简单的一维完全背包问题了。


但要注意的是每个度数的价值应该转化为它与度数为1的价值的差值再注意下初始化就没问题了。


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

typedef long long ll;
const int maxn = 2020;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;

int val[maxn];
int dp[maxn*2];

int main()
{
    int n;
    rush()
    {
        scanf("%d",&n);
        for(int i=0;i<n-1;i++)
        {
            scanf("%d",&val[i]);
            if(i!=0)    val[i]-=val[0];
        }
        mst(dp,-1);
        dp[0]=n*val[0];
        int V=n-2;
        for(int i=1;i<n;i++)
        for(int j=i;j<=V;j++)
        {
            dp[j]=max(dp[j],dp[j-i]+val[i]);
        }
        printf("%d\n",dp[V]);
    }
    return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值