WUSTOJ 1299: 结点选择(Java)

108 篇文章 0 订阅
80 篇文章 18 订阅
题目链接:?1299: 结点选择
参考:?【Java】 蓝桥杯ALGO-4 算法训练 结点选择——柳婼 の blog
Description

有一棵n个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?

Input

多组测试数据
每组第一行包含一个整数n
接下来的一行包含n个正整数,第i个正整数代表点i的权值。
接下来一共n-1行,每行描述树上的一条边。

Output

输出一个整数,代表选出的点的权值和的最大值。

Simple Input
5
1 2 3 4 5
1 2
1 3
2 4
2 5
Sample Output
12
Hint

样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。

数据规模与约定
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。

分析?

树的存储结构原本可以用“孩子表示法”,可是此题的输入并不是先父结点后子结点,因此,我们不妨用无向图来看待此树(树其实也是图)。而此题结点数比较大,用“数组表示法”显然不合适(内存可能不够),“十字链表”和“邻接多重表”则比较繁琐,“邻接表”作为存储结构最为合适。

采用先序遍历的算法遍历整棵树。

当前子树的根结点可以选择,可以不选择。
如果根结点不选择,那么它的某个子结点可不选择,也可选择。只需选取其中权值较大的那种加到根结点的权值中即可。
如果根结点选择,那么它的所有子结点都不能选择。也就是将子结点不选择的那种的权值加到根结点权值中即可。

选择当前子树的根结点,那么就将它的子结点(子树)i的权值较大的情况加到根结点中
weight[root][0] += Math.max(weight[i][0], weight[i][1]);
选择当前子树的根结点,那么将它的子结点(子树)i的不选择的权值加到根结点中
weight[root][1] += weight[i][0];

代码?
/**
 * Time 3505ms
 * @author wowpH
 * @version 1.1
 * @date 2019年6月7日上午10:57:35
 * Environment:	Windows 10
 * IDE Version:	Eclipse 2019-3
 * JDK Version:	JDK1.8.0_112
 */

import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
	private Scanner sc;
	private static final int MAX_N = 100001;
	private int n;
	private int[][] weight;// 权值
	private List<List<Integer>> adjacencyList;// 邻接表

	public Main() {
		weight = new int[MAX_N][2];// 下标从1开始
		sc = new Scanner(new InputStreamReader(System.in));
		while (sc.hasNext()) {
			adjacencyList = new ArrayList<List<Integer>>();// 头指针的线性表
			input();
			dfs(1, 0);// 1根节点,0无前驱结点
			System.out.println(Math.max(weight[1][0], weight[1][1]));
		}
		sc.close();
	}

	private void input() {
		n = sc.nextInt();// 结点数
		adjacencyList.add(new ArrayList<Integer>());// 下标从1开始,这个不用
		for (int i = 1; i <= n; i++) {
			weight[i][0] = 0;			// 初始化为0
			weight[i][1] = sc.nextInt();// 输入权值
			adjacencyList.add(new ArrayList<Integer>());// 创建头结点
		}
		int head, tail;// 弧的头尾
		for (int i = 1; i < n; i++) {
			tail = sc.nextInt();
			head = sc.nextInt();
			adjacencyList.get(tail).add(head);// 添加表结点
			adjacencyList.get(head).add(tail);// 无向图,添加表结点
		}
	}

	private void dfs(int root, int pre) {// root根,pre前驱结点
		List<Integer> list = adjacencyList.get(root);// 当前链表
		for (Integer i : list) {
			if (i != pre) {// 非叶子结点,继续向下递归
				dfs(i, root);
				// 不选root点,选root子结点i最大的情况
				weight[root][0] += Math.max(weight[i][0], weight[i][1]);
				// 选root点,不选root子结点i的情况
				weight[root][1] += weight[i][0];
			}
		}
	}

	public static void main(String[] args) {
		new Main();
	}
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值