洛谷P2015 苹果二叉树(树形dp)

题意分析

给出一个N个点的二叉树,树上有边权,求留下Q个树枝能够获得的最大收益为多少。

dp[i][j] d p [ i ] [ j ] 表示在以 i i 为根的节点,留下 j j 个分支,的最大收益值。

u u 为当前遍历到的根节点, v v 为访问的子节点, e[i].w e [ i ] . w 当前边的边权。则状态转移方程如下:
dp[u][j]=max(dp[u][j],dp[u][jk]+dp[v][k1]+e[i].w) d p [ u ] [ j ] = m a x ( d p [ u ] [ j ] , d p [ u ] [ j − k ] + d p [ v ] [ k − 1 ] + e [ i ] . w )
还要注意循环顺序,循环j要从m到0,而k是任意的,这与转移的顺序有关系

#include "bits/stdc++.h"
using namespace std;
const int nmax = 1e6 + 10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef struct {
    int to, nxt, w;
} Edge;
Edge e[nmax << 1];
int dp[1010][1010];
int head[nmax], tot, n, m;
void init() {
    memset(head, -1, sizeof head);
    tot = 0;
}
void add(int u, int v, int w) {
    e[tot].to = v;
    e[tot].nxt = head[u];
    e[tot].w = w;
    head[u] = tot++;
}
void getdp(int u , int fa) {
    for (int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if (v != fa) getdp(v, u);
        else continue;
        for (int j = m; j >= 0; --j)
            for (int k = j ; k >= 1 ; --k)
                dp[u][j] = max(dp[u][j], dp[u][j - k] + dp[v][k - 1] + e[i].w);
    }
}
int main() {
    init();
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n - 1; ++i) {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w); add(v, u, w);
    }
    getdp(1, -1);
    printf("%d\n", dp[1][m]);
    return 0;
}

你可能感兴趣的:(算法---动态规划)