删边使每个连通块权值和为 target

思路

树形 DP。

设 sum[u] 表示以 u 为根的子树权值和。

如果 sum[u] == target,则可以断开 u 与父节点的边,形成一个合法连通块。

但 target 可能为 0,且 val 可能为负,因此不能简单贪心。

需要 DFS 后序处理,统计每个子树能否独立成块。

设 dp[u] 表示以 u 为根的子树中,能形成的合法连通块数量。

若 sum[u] == target,则 dp[u]++,并将 sum[u] 置为 0,表示这个块已经独立。

最后如果整棵树的 sum[root] == target 或 sum[root] == 0 且 root 已被处理,则答案有效。

代码

c

复制代码
#include <stdio.h>
#include <stdlib.h>

#define MAXN 200005

typedef struct Edge {
    int to, next;
} Edge;

Edge edges[MAXN * 2];
int head[MAXN], edgeCnt = 0;
int val[MAXN];
long long sum[MAXN];
int dp[MAXN];
int target;
int ans = 0;

void addEdge(int u, int v) {
    edges[++edgeCnt] = (Edge){v, head[u]};
    head[u] = edgeCnt;
}

void dfs(int u, int parent) {
    sum[u] = val[u];
    for (int e = head[u]; e; e = edges[e].next) {
        int v = edges[e].to;
        if (v == parent) continue;
        dfs(v, u);
        sum[u] += sum[v];
        dp[u] += dp[v];
    }

    if (sum[u] == target) {
        dp[u]++;
        sum[u] = 0;
    }
}

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
    scanf("%d", &target);

    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        addEdge(u, v);
        addEdge(v, u);
    }

    dfs(1, 0);

    if (sum[1] == 0 && dp[1] > 0)
        printf("%d\n", dp[1] - 1);
    else
        printf("-1\n");

    return 0;
}
相关推荐
xxwl5851 小时前
区域赛算法模版第四章---数据结构
数据结构·c++·算法
xxwl5852 小时前
第六章---计算几何
笔记·学习·算法
Logic1013 小时前
C语言/数据结构二维数组题解:找出行列O个数均为偶数的格子——奇偶性预处理+二次遍历
c语言·数据结构·算法·二维数组·时间复杂度·动态内存分配·奇偶性
程序猿阿森3 小时前
【机器学习实战】朴素贝叶斯算法详解:从概率基础到商品评论情感分析
算法·机器学习·概率论
xxwl5853 小时前
区域赛算法模版第五章---数学与数论
c++·笔记·算法
看浪的路人3 小时前
第6讲:Agent 安全体系——Prompt 注入防御、工具调用审计与输出合规
人工智能·算法
局部有解3 小时前
LeetCode Hot100 438 找到字符串中所有字母异位词
c++·算法·leetcode
垆边人似月.4 小时前
移动长度 k 子串使字符串变成回文
数据结构·算法
pride.li4 小时前
第12章 Python 教程-流程控制:循环结构
linux·服务器·python·算法