HDU - 5534 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 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

题解:

因为n-1条边要连接所有的点,所以我们可以先让每条边与一个点一对一连接,那么我们得到(n-1)个度为一的点,剩下一个度为0的是根节点,然后我们让一条边与根节点相连,那么现在n个点的度都为一,因为所有边共产生2*(n-1)度所以剩下(n-2)度,所以问题转化成把(n-2)个度分给n个点,使得结果的f(d)和最大。

这明显是一个完全背包问题了。可以把度数想成weight,f(d)想成value,(n-2)为背包最大容量,那么这就是一个基础的完全背包放东西模板。

注意这里d 和 f(d)都为原值与1和f(1)的差值,也因此会有负数。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 2020;
const long long INF = 0x3f3f3f3f3f3f3f3f;

struct D{
	long long f,d;
}board[MAXN];

long long dp[MAXN*2];

int main(){	
	
	int T,N;
	scanf("%d",&T);
	while(T--){
		memset(dp,-INF,sizeof dp);
		scanf("%d",&N);
		scanf("%lld",&board[1].f);
		board[1].d = 1;
		for(int i=2 ; i<N ; ++i){
			long long t;
			scanf("%lld",&t);
			board[i].f = t - board[1].f;
			board[i].d = i-1;
		}
		dp[0] = 0;
		long long re = N*board[1].f;
		for(int i=2 ; i<N ; ++i){
	        for(int j=board[i].d ; j<=N-2 ; ++j){
	            if(dp[j-board[i].d] != -INF)dp[j] = max(dp[j],dp[j-board[i].d]+board[i].f);   
	        }
	    }
		printf("%lld\n",re+dp[N-2]);
	}
	
	return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值