HDU 5534 Partial Tree (变形完全背包 好题)


Partial Tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)

Total Submission(s): 462    Accepted Submission(s): 236

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 n1 edges. You want to complete this tree by adding n1 edges. There must be exactly one path between any two nodes after adding. As you know, there are nn2 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 n1 integers f(1),f(2),,f(n1) .

1T2015
2n2015
0f(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
 
Source
2015ACM/ICPC亚洲区长春站-重现赛(感谢东北师大)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5534

题目大意:构造一棵树,已知度为i的点的值为f[i],现在求怎么构造这个树可以使总的数值最大,求最大的数值

题目分析:长春银牌题,这题第一反应是二维n3方的背包,显然做不了,一棵n个点的树的总度数为2n-2,并且每个点的度数至少为1,因此我们可以先给每个点一个度为1的值,总值即n*f[1],然后对剩下的n-2的度做完全背包(dp[i]表示用了i度能得到的最大价值),再分配的时候每个点已经有了一个度,要变换一下度值关系,而且dp要初始化为负无穷,因为变换后的f可能小于0(比如度为2的点的权值比度为1的小)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int const MAX = 2200;
int const INF = 0x3fffffff;
int dp[MAX], f[MAX], n;

int main()
{
	int T;
	scanf("%d", &T);
	while(T --)
	{
		int n;
		scanf("%d", &n);
		for(int i = 0; i <= n; i++)
			dp[i] = -INF;
		for(int i = 1; i <= n - 1; i++)
			scanf("%d", &f[i]);
		int val1 = n * f[1];
		for(int i = 2; i <= n - 1; i++)
			f[i] -= f[1];
		for(int i = 1; i <= n - 2; i++)
			f[i] = f[i + 1];
		dp[0] = 0;
		for(int i = 1; i <= n - 2; i++)
			for(int j = i; j <= n - 2; j++)
				dp[j] = max(dp[j], dp[j - i] + f[i]);
		printf("%d\n", dp[n - 2] + val1);
	}
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,这是一道关于二叉树的问题,需要输出每个二叉树的层序遍历。如果二叉树没有完全给出,则输出“not complete”。而且,这道题目是一个ACM竞赛的题目,需要使用Java语言进行编写。 以下是Java语言的代码实现: ```java import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String s = sc.nextLine(); if (s.equals("")) { continue; } String[] arr = s.split(" "); int len = arr.length; int[] tree = new int[len]; boolean[] flag = new boolean[len]; for (int i = 0; i < len; i++) { if (arr[i].equals("()")) { tree[i] = -1; flag[i] = true; } else { tree[i] = Integer.parseInt(arr[i].substring(1, arr[i].length() - 1)); } } int root = 0; for (int i = 0; i < len; i++) { if (!flag[i]) { root = i; break; } } boolean isComplete = true; Queue<Integer> queue = new LinkedList<>(); queue.offer(root); int index = 1; while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { int cur = queue.poll(); if (tree[cur] == -1) { if (index < len && !flag[index]) { isComplete = false; } } else { if (cur * 2 + 1 < len) { queue.offer(cur * 2 + 1); if (tree[cur * 2 + 1] != -1) { flag[cur * 2 + 1] = true; } } if (cur * 2 + 2 < len) { queue.offer(cur * 2 + 2); if (tree[cur * 2 + 2] != -1) { flag[cur * 2 + 2] = true; } } } index++; } } if (!isComplete) { System.out.println("not complete"); continue; } queue.offer(root); StringBuilder sb = new StringBuilder(); while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { int cur = queue.poll(); sb.append(tree[cur]).append(" "); if (cur * 2 + 1 < len && tree[cur * 2 + 1] != -1) { queue.offer(cur * 2 + 1); } if (cur * 2 + 2 < len && tree[cur * 2 + 2] != -1) { queue.offer(cur * 2 + 2); } } } System.out.println(sb.toString().trim()); } } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值