下载pdf,获得更好阅读体验。
提取码:ke7w。

upd:这好像是 08 年哪个省省选题原题

题意转化

毒瘤出题人把 放在最后,害得眼睛不好的选手一开始没看到想了好长时间...

为一棵树

那这样就是一棵根为 的树上删除若干条边,使得所有叶子结点都与根不连通。


树形 DP

画一棵树,假设 个子树

根据 DP 子问题的思想,我们已经知道了下面 个子树,使得其叶子结点不能到 的最小代价。

此时,对于子树 ,有两种方案:一种是采取子树决策的方案,一种是删掉 的边,显然取最小更优。

对于叶子结点,子树决策为 即可。


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

const int maxn = 100000 + 7;
const int maxm = 200000 + 7;
const long long INF = 0x3f3f3f3f3f3f3f3fll;

int n, m, S;
int Head[maxn], Next[maxm], to[maxm], tot, w[maxm];

long long dp[maxn];

void addedge(int x, int y, int z) {
    to[++tot] = y, Next[tot] = Head[x], Head[x] = tot, w[tot] = z;
}
void add(int x, int y, int z) {
    addedge(x, y, z); addedge(y, x, z);
}

void dfs(int x, int f) {
    bool son = false;
    for(int i = Head[x]; i; i = Next[i]) {
        int y = to[i];
        if(y == f) continue;
        son = true;
        dfs(y, x);
        dp[x] += min((long long)w[i], dp[y]);
    }
    if(!son) dp[x] = INF;
}

int main(void) {
    scanf("%d%d%d", &n, &m, &S);
    for(int i = 1, x, y, z; i < n; i++) {
        scanf("%d%d%d", &x, &y, &z);
        add(x, y, z);
    }
    dfs(S, 0);
    printf("%lld\n", dp[S]);
}

另一种做法

这种做法可以解决一般图的问题

作为超级源点,所有度为 的点连接超级汇点,跑一遍最小割。

代码就是贴个模板的事情,就不放了。