删边使每个连通块权值和为 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;
}
相关推荐
octopus_c1 小时前
STL 之 string:auto 与范围 for、常用接口、模拟实现与深浅拷贝
开发语言·c++·算法
老师我太想进步了202616 小时前
【数据结构-4】算法美学之顺序表
数据结构·算法
风影同志7832416 小时前
编码器是激活函数吗?—— 一个看起来很像、其实不是的类比
算法
UIU11416 小时前
P1481 魔族密码
c++·算法·动态规划
加宝的起点雷达19 小时前
40 条候选里 38 条来自同一个源,主卡整屏重样
人工智能·算法·创业
秋天的怀念_David19 小时前
算法一千零一夜 · 第二十六夜 协议的母语
java·spring boot·算法
闻缺陷则喜何志丹1 天前
【C++特性】四种类型转
c++·算法·类型转换
喵本喵叁肆1 天前
用 Boosting 把弱隐私算法炼成强隐私算法(英文原题:Boosting and Differential Privacy (FOCS 2010))
算法·集成学习·boosting