Codeforces1689C - Infected Tree(树形DP)

题目链接:https://codeforces.com/problemset/problem/1689/C
题意:给定一棵树,除根节点的度数最多为2,其他节点的度数最多为3。有一个病毒从根节点开始向下蔓延,每次病毒会向其下一层的所有子节点蔓延,同时每次我们可以选择删除一个节点,那么以该节点为根的所有子节点就被救下来不会被感染了(不包括删去的节点)。问最多能救下来多少节点。
思路:简单的树形DP,我们可以用 D P [ u ] DP[u] DP[u]表示以点u被感染,能救下来的子节点的个数。因为除根节点外的其他节点的度数最多为3,那么每个节点最多有2个子节点,对于每个节点我们每次会选取其中一个子节点删除,用 s z [ u ] sz[u] sz[u]表示以点u为根的子节点的个数, s 1 , s 2 s1,s2 s1,s2表示点u的两个子节点,那么删除 s 1 s1 s1的答案就是 s z [ s 1 ] − 1 + d p [ s 2 ] sz[s1]-1+dp[s2] sz[s1]1+dp[s2],如果删除 s 2 s2 s2,那么答案就是 s z [ s 2 ] − 1 + d p [ s 1 ] sz[s2]-1+dp[s1] sz[s2]1+dp[s1],还要特判一下对于每个节点只有一个儿子和没有儿子的情况,具体看代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <cmath>
#include <queue>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int N = 1e5 + 10,INF=1e9;

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    
    int T;cin>>T;
    while(T--)
    {
        int n;cin>>n;
        vector<vector<int>>g(n+1);
        for(int i=0;i<n-1;i++)
        {
            int u,v;cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
        }

        vector<int>sz(n+1,0),dp(n+1,0);

        auto dfs = [&](auto&& dfs,int u,int fa)->int
        {
            sz[u]=1;
            int s1=-1,s2=-1;//表示点u的两个子节点

            for(auto j:g[u])
            {
                if(j==fa)continue;
                dfs(dfs,j,u);
                sz[u]+=sz[j];//统计以点u为根节点的子节点个数

                if(s1==-1)s1=j;
                else if(s2==-1)s2=j;
            }
            if(s1==-1)return dp[u]=0;//特判没有子节点的情况
            if(s2==-1)return dp[u]=sz[s1]-1;//特判只有一个子节点的情况
            return dp[u]=max(sz[s1]-1+dp[s2],sz[s2]-1+dp[s1]);//有两个子节点的情况
        };
        cout<<dfs(dfs,1,-1)<<"\n";;
        
    }
    return 0;
}
  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值