NC22598 Rinne Loves Edges

题意

一棵根为\(S\)的树,选择性切掉一些边,求使得所有的叶子都不能到达根的最小代价。

思路

树形\(DP\)

树型\(DP\)本质上可以说是个搜索——遍历这棵树,在返回的时候维护相关的值。

不管是写\(DP\)还是写搜索其实都是要分析原问题和子问题分别是什么的,我们的原问题是以\(S\)为根的子树删掉权值和尽量小的一些边使得\(S\)和一个叶子节点都不连通,那么子问题也很简单,就是求以\(x\)为根的子树删掉一些边使得\(S\)\(x\)的子树上每个叶子节点都不连通。

状态表示:

\(f(u)\):使得以\(u\)为根的子树内的叶子到不了\(u\)的最小代价。

状态转移:

要想在考虑\(u\)这个点的子树的时候就实现子树上每个叶子都和\(u\)不连通,那么有两种情况:把\(u\)和他的儿子断开,或者是,在\(u\)的子树上去把所有叶子节点都断开。

\[f(u)=\sum_{Son(x)}\min(f(x),w[u\rightarrow x]) \]

边界:

所有的叶子节点\(f\)值应为一个极大值。

const int N=1e5+10;
vector<PII> g[N];
LL f[N];
int n,m,s;

void dfs(int u,int fa)
{
    bool leaf=true;
    for(int i=0;i<g[u].size();i++)
    {
        int j=g[u][i].fi,w=g[u][i].se;
        if(j == fa) continue;
        leaf=false;
        dfs(j,u);
        f[u]+=min(f[j],(LL)w);
    }

    if(leaf) f[u]=LNF;
}

int main()
{
    cin>>n>>m>>s;

    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a].pb({b,c});\
        g[b].pb({a,c});
    }

    dfs(s,-1);

    cout<<f[s]<<endl;
    //system("pause");
    return 0;
}

posted @ 2021-04-14 09:15  Dazzling!  阅读(21)  评论(0编辑  收藏  举报