最大权值和

一、题目

问题描述

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

第一行包含一个整数 n 。

接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。

接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择345号点,权值和为 3+4+5 = 12 。
数据规模与约定

对于20%的数据, n <= 20。

对于50%的数据, n <= 1000。

对于100%的数据, n <= 100000。

权值均为不超过1000的正整数。

二、分析

1、设dp[i][1]为编号为i的节点被选中时的最大权值,dp[i][0]为编号为i的节点不被选中时的最大权值和。
2、通过二维数组来表示树,即tree[i][j]代表编号i的第j+1个孩子节点的编号

public class Question4 {
    // dp[i][1]表示第i个节点被选中时对应的权值,否则没有被选中
    public static int[][] dp = new int[100002][2];
    // 用二维数组(邻接矩阵)来表示树
    // tree[i][3] =num表示第i个节点的第3个孩子节点为第num个节点
    public static int[][] tree = new int[100002][300];

    /**
     * 
     * @param point1
     * @param point2
     */
    public static void creatTree(int point1, int point2) {
        int i = 0;
        // 当第point1个节点为父母节点时
        while (tree[point1][i] != 0)
            i++; // 如果第point1个节点已经有孩子了,再增加一个孩子
        tree[point1][i] = point2;// 表示第point1个节点第i+1个孩子为point2
        int j = 0;
        // 当第point2个节点为父母节点时
        while (tree[point2][j] != 0)
            j++;
        tree[point2][j] = point1;// 表示第point2个节点的第j+1个孩子是point1
    }

    /*
     * 参数satrt:开始对树进行DFS遍历的开始节点,为具体节点位置,不是节点权值 参数root:为第start个节点的直接父母节点位置,
     * root=0表示根节点的父母节点
     */
    public static void dfs(int start, int root) {
        int child = tree[start][0]; // 第start个节点的第1个孩子节点
        for (int i = 0; child != 0; i++) {
            child = tree[start][i];
            if (child != root) { // 防止出现start的孩子成为start的父亲情况
                dfs(child, start);
                // 状态转移方程
                dp[start][1] += dp[child][0];
                dp[start][0] += (dp[child][1] > dp[child][0] ? dp[child][1] : dp[child][0]);
            }
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        for (int i = 0; i < n; i++)
            dp[i + 1][1] = in.nextInt();
        for (int i = 0; i < n - 1; i++) {
            int point1 = in.nextInt();
            int point2 = in.nextInt();
            creatTree(point1, point2);
        }
        dfs(1, 0); // 从创建的数的根节点(即第1个顶点,0表示根节点的父母节点)开始进行DFS遍历
        int max = (dp[1][1] > dp[1][0] ? dp[1][1] : dp[1][0]);
        System.out.println(max);
    }
}

Weep no more,no sigh,nor groan,Sorrow calls no time that’s gone.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个用C++实现的解决方案,使用了深度优先搜索(DFS)和动态规划(DP)的思想: ```cpp #include <iostream> #include <vector> #include <cstring> using namespace std; const int MAXN = 1005; vector<int> graph[MAXN]; int weight[MAXN]; int dp[MAXN][MAXN]; // 深度优先搜索,计算每个节点到起点的最大和最小权值 void dfs(int cur, int parent) { dp[cur][0] = dp[cur][1] = weight[cur]; for (int i = 0; i < graph[cur].size(); i++) { int next = graph[cur][i]; if (next == parent) continue; dfs(next, cur); for (int j = 1; j <= cur; j++) { if (dp[next][j-1] != -1) { dp[cur][j] = max(dp[cur][j], dp[next][j-1] + weight[cur]); dp[cur][j-1] = min(dp[cur][j-1], dp[next][j-1] + weight[cur]); } } } } int main() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> weight[i]; } for (int i = 0; i < m; i++) { int x, y; cin >> x >> y; graph[x].push_back(y); graph[y].push_back(x); } memset(dp, -1, sizeof(dp)); dfs(1, 0); int ans = 0; for (int i = 0; i <= n; i++) { if (dp[1][i] != -1) { ans = max(ans, dp[1][i] - dp[1][0]); } } cout << ans << endl; return 0; } ``` 这段代码实现了对每个节点到起点的最大和最小权值的计算,最后找出最大权值和最小权值之差的最大值作为答案。其中,`graph`数组存储了每个节点的相邻节点,`weight`数组存储了每个节点的权值,`dp`数组用于动态规划计算。通过深度优先搜索遍历每个节点,并更新`dp`数组的值,最后找出最大差值输出。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值