首页 > 其他分享 >树形dp

树形dp

时间:2023-02-02 19:22:53浏览次数:57  
标签:连通 vector int 子树 树形 dp 分量

大佬博客

  由于树形dp种类繁多,而且大佬博客中总结的很好,这里我就只记录下我写到的树形dp

 

《F - Components》

  

 

 简单的来说就是:

  给一颗有n个节点的树,因为对于有n个节点的树,其n个节点有个点集

 

 

  现在问:由这,每个点集会形成h个连通分量

 

 

      求连通分量为时,所对应的点集个数

 

 

 

 

 

 当根u,其下有多个子树,我们从左到右枚举这些子树,

然后将其情况与根u的dp数组合并(即状态合并)

合并时,如图中描述的:

  

 

 

 

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 5001, mod = 998244353;
vector<int> sides[N];
// dp[u][i][0/1]:表示以u为根节点的子树,当1时,u在点集中,当0时,u不在点集中
// 而且形成的连通分量的数量恰好为i的方案数
int n;
vector<vector<vector<int>>> dp(N, vector<vector<int>>(N, vector<int>(2)));
int dfs(int u, int f)
{
    dp[u][1][1] = 1, dp[u][0][0] = 1;
    // nows为当前以u为根节点的子树中最大能够形成的连通分量的数
    // sons为某一子树中最大能够形成的连通分量的数
    int nows = 1, sons;
    for (int i = 0; i < sides[u].size(); i++)
    {
        int to = sides[u][i];
        if (to == f)
            continue;
        sons = dfs(to, u);
        vector<vector<int>> t(n + 1, vector<int>(2));
        // l是枚举当前以u为根节点的子树能够形成连通分量为l
        // r是枚举u的其中一个子树能够形成连通分量为r
        for (int l = 0; l <= nows; l++)
            for (int r = 0; r <= sons; r++)
            {
                t[l + r][0] = (t[l + r][0] +
                               (ll)dp[u][l][0] * (dp[to][r][1] + dp[to][r][0]) % mod) %
                              mod;
                t[l + r][1] = (t[l + r][1] +
                               (ll)dp[u][l][1] * dp[to][r][0] % mod) %
                              mod;
                if (l + r - 1 >= 0)
                    t[l + r - 1][1] = (t[l + r - 1][1] +
                                       (ll)dp[u][l][1] * dp[to][r][1] % mod) %
                                      mod;
            }
        nows += sons;
        dp[u].swap(t);
    }
    return nows;
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n - 1; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        sides[a].push_back(b), sides[b].push_back(a);
    }
    dfs(1, -1);
    for (int i = 1; i <= n; i++)
        cout << (dp[1][i][0] + dp[1][i][1]) % mod << endl;
    return 0;
}

 

 

 

 

 

 

  

标签:连通,vector,int,子树,树形,dp,分量
From: https://www.cnblogs.com/cilinmengye/p/17087047.html

相关文章

  • 数位DP
    数位DPTODO补充数位\(DP\)概念等补充题目分析及过程增加题目题目CF1073E.SegmentSumCF1073E.SegmentSum求\(L\simR\)之间最多不包含\(K\)个数码的......
  • 【YBT2023寒假Day4 A】网格染色(DP)(矩阵乘法)(DFT)
    网格染色题目链接:YBT2023寒假Day4A题目大意有一个n*3的网格,你可以选恰好m个格子染成黑色。然后对于一个黑点,我们对它周围的\(8\)个点中的一些有限制不能是黑点,......
  • Codeforces1778E 【线性基】【换根DP】
    我,差30秒,就能AC这道题,我知道错哪的时候是倒计时30,不记得优先级想赌一把,因为我没有先写括号的习惯,所以倒计时14的时候交了,然后想改了括号再交一发,改了括号之后,比赛结束了。......
  • C/C++ Socket UDP 广播消息的发送与接收
    C/C++SocketUDP广播消息的发送与接收局域网内全网段广播消息的IP地址为:255.255.255.255,向该IP地址发送广播消息,局域网下的任何网段的客户机都能收到广播。对于发送端,如果......
  • 利用natapp实现TCP、UDP内网穿透
    利用natapp实现TCP、UDP内网穿透natapp官网:​​https://natapp.cn/​​下载:下载下来其实就只有一个文件:首先在natapp官网上注册一个账号,并实名认证,这一步是必须的!然后去购买......
  • Ubuntu错误:E: Could not open lock file /var/lib/dpkg/lock-frontend
    Ubuntu错误:E:Couldnotopenlockfile/var/lib/dpkg/lock-frontendubuntu使用apt下载和更新软件的时候,出现了以下错误:E:Couldnotopenlockfile/var/lib/dpkg/lock-f......
  • 数位DP
    一、常见题面求两个数之间的满足特定条件的数的方案数(提高+/省选-位数为\(10^6\);省选/NOI-位数为\(10^{18}\)or有一些奇奇怪怪的操作)例子:待完善求两个数之间......
  • 开发用工具类2.0:无侵入式的树形状工具类TreeUtils
    packagecn.jow.util;importjava.util.*;importjava.util.function.Function;importjava.util.stream.Collectors;/***无侵入方式处理对象集合,树形状结构数......
  • ThreadPoolExecutor线程池参数设置技巧
    一、ThreadPoolExecutor的重要参数1、corePoolSize:核心线程数*核心线程会一直存活,及时没有任务需要执行*当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建......
  • JavaFX 网格布局 GridPane
    packagefx.com;importjavafx.application.Application;importjavafx.scene.Scene;importjavafx.scene.control.Button;importjavafx.scene.image.Image;importjavafx.......