树形dp:Vertex Deletion

The 15th Chinese Northeast Collegiate Programming Contest

  • 正文
    • 题目描述
    • 题目思路及代码
  • 结语

正文

题目描述

给出一棵树,每次可以删去任意点,要求删完后不能有孤立的点,求方案数。

题目思路及代码

大概很容易看出来是个树形dp,状态不太好想。
d p [ u ] [ 0 ] 表示删去这个点
d p [ u ] [ 1 ]表示不删这个点,而且删去所有子节点
d p [ u ] [ 2 ] 表示不删这个点,而且至少留一个子节点
对于第一种情况,此时的u一定满足条件;
对于第二种情况,要求u的父亲节点也不被删去才可以满足条件;
对于第三种情况,此时的u已经满足条件了。

dp[x][0]=(dp[v][0]+dp[v][2])%mod*dp[x][0]%mod;
dp[x][1]=dp[v][0]*dp[x][1]%mod;

如果删去u的话,那么想让子节点v满足条件,可以删除v,也可以不删v并且至少保留v的一个子节点;
如果不删u并且删去所有子节点的话,说明节点v是被删除的状态。
对于dp[u][2]可以用所有合法的方案数减去不合法的方案数。
最后答案就是dp[1][0]+dp[1][2]

#include
using namespace std;
typedef long long int ll;
const ll maxn=2e5+10;
const ll mod=998244353;
vector<ll> g[maxn];
ll n,t;
ll dp[maxn][10];
//ll vis[maxn];
void dfs(ll x,ll u){
    //cout<
    dp[x][0]=dp[x][1]=dp[x][2]=1;
    for(int i=0;i<g[x].size();i++){
        ll v=g[x][i];
        if(v==u)continue;
        dfs(v,x);
        dp[x][0]=(dp[v][0]+dp[v][2])%mod*dp[x][0]%mod;
        dp[x][1]=dp[v][0]*dp[x][1]%mod;
        dp[x][2]=(dp[v][0]+dp[v][1]+dp[v][2])%mod*dp[x][2]%mod;
    }
    dp[x][2]=(dp[x][2]-dp[x][1]+mod)%mod;
    //cout<
    return ;
}
int main()
{
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);
        for(int i=1;i<n;i++){
            ll x,y;
            scanf("%lld%lld",&x,&y);
            g[x].push_back(y);
            g[y].push_back(x);
        }
        dfs(1,-1);
        ll ans=0;
        ans=(ans+dp[1][0]+dp[1][2])%mod;
        printf("%lld\n",ans);
        for(int i=1;i<=n;i++){
            g[i].clear();
           // cout<
            dp[i][0]=dp[i][1]=dp[i][2]=0;

        }
    }
    return 0;
}

结语


“遇事不决,可问春风。春风不语,即随本心。”的意思是:对一件事犹豫不决,就问春风该如何做,春风给不出答案,就凭自己本心做出决断。“遇事不决可问春风,春风不语即随本心”一句出自网络作家“烽火戏诸侯”的《剑来》,其原文是:“遇事不决,可问春风。春风不语,遵循己心”。

树形dp:Vertex Deletion_第1张图片


你可能感兴趣的:(竞赛,深度优先,动态规划,图论)