Tree Coverage Dynamic Programming Optimization

Tree Coverage DP Model

The tree coverage dynamic programming model addresses optimization problems where nodes are selected on a tree structure. Each chosen node can cover all nodes within a specified distance, with the goal of solving various optimization tasks (counting problems are not applicable).

State Definition and Transition

Let f[i][j] represent the optimal value after processing the subtree rooted at node i, where node i is either uncovered or specifically covered by node j.

Let best[i] store the optimal solution for node i.

The transition involves enumerating which node covers the current node u, then adjusting for overcounted costs. The recurrence relation becomes:

f[u][i] += max(best[v], f[v][i] + s - w[i])

This approach effectively reassigns the cost contribution of node i to the root node u. While the transition may appear discontinuous, the optimal substructure property ensures that all necessary states are captured within the best array.

Implementation Example

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int MAXN = 1005;
const ll INF = 1e18;

ll dist[MAXN][MAXN], cost[MAXN], dp[MAXN][MAXN], optimal[MAXN];
ll n, multiplier, radius, penalty;
vector<pair<int,int>> adjacency[MAXN];

void computeDistances(int node, int parent, int root) {
    for(auto& edge : adjacency[node]) {
        if(edge.first != parent) {
            dist[root][edge.first] = dist[root][node] + edge.second;
            computeDistances(edge.first, node, root);
        }
    }
}

void treeDP(int node, int parent) {
    for(auto& edge : adjacency[node]) {
        if(edge.first != parent) {
            treeDP(edge.first, node);
        }
    }
    
    for(int i = 1; i <= n; ++i) {
        dp[node][i] = (dist[node][i] <= radius ? cost[node] : 0) - penalty;
        for(auto& edge : adjacency[node]) {
            if(edge.first != parent) {
                dp[node][i] += max(optimal[edge.first], dp[edge.first][i] + penalty);
            }
        }
    }
    
    for(int i = 1; i <= n; ++i) {
        optimal[node] = max(optimal[node], dp[node][i]);
    }
}

int main() {
    scanf("%lld%lld%lld%lld", &n, &multiplier, &radius, &penalty);
    
    for(int i = 1; i <= n; ++i) {
        scanf("%lld", &cost[i]);
        cost[i] *= multiplier;
    }
    
    for(int i = 1; i < n; ++i) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        adjacency[u].push_back({v, w});
        adjacency[v].push_back({u, w});
    }
    
    for(int i = 1; i <= n; ++i) {
        computeDistances(i, 0, i);
    }
    
    treeDP(1, 0);
    printf("%lld\n", optimal[1]);
    
    return 0;
}

Correctness Analysis

The optimal array serves a crucial role in maintaining solution validity. The state definition enforces that each node is either uncovered or explicitly covered by a specific node. This constraint prevents invalid configurations where a parent node is assigned to a distant cover while its child is optimally covered by a closer node. Although such assignments might initially seem problematic, the optimal substructure guarantees that any invalid state will have a superior valid alternative already represented in the optimal values.

Tags: dynamic-programming tree-algorithms Optimization graph-theory

Posted on Mon, 24 Aug 2026 16:37:35 +0000 by muralimohan001