不会树形dp

#include <bits/stdc++.h>
using namespace std;
const int N=2e3+50;
const int MOD=998244353;
typedef long long ll;
int n,k;
int u,v;
int cnt;
int head[N];
struct Edge{
   
    int v,next;
}edge[N<<1];
void init(){
   
    cnt=0;
    memset(head,-1,sizeof(head));
}
void addEdge(int u,int v){
   
    edge[cnt]=Edge{
   v,head[u]};
    head[u]=cnt++;
    edge[cnt]=Edge{
   u,head[v]};
    head[v]=cnt++;
}
ll dp[N][N],sz[N],tmp[N];
void dfs(int u,int p){
   
    //只有自身一个节点的情况
    //sz保存包括自身的所有子节点数
    //dp[i][j]表示只考虑根为i的子树,包含节点i的联通块大小为j的方案个数
    //dp[i][0]表示dp[i][1]+...+dp[i][k]
    sz[u]=dp[u][1]=1;
    for(int t=head[u];t!=-1;t=edge[t].next){
   
        int v=edge[t].v;
        if(v==p){
   
            continue;
        }
        dfs(v,u);
        //??
        memset(tmp,0,sizeof(tmp));
        //这里不是遍历u的所有子节点,而是遍历所有子孙节点
        for(int i=1;i<=sz[u];i++){
   
            for(int j=0;j<=sz[v] && i+j<=k;j++){
   
                //u提供连通分量的i个 v(u的子节点,与u相连)提供j个,连起来该连通分量大小就是i+j
                tmp[i+j]=(tmp[i+j]+(dp[u][i]*dp[v][j])%MOD)%MOD;
            }
        }
        for(int i=0;i<=k;i++){
   
            dp[u][i]=tmp[i];
        }
        sz[u]+=sz[v];
    }
    for(int i=1;i<=k;i++){
   
        dp[u][0]=(dp[u][0]+dp[u][i])%MOD;
    }
}
int main(void){
   
    freopen("data.txt","r",stdin);
    scanf("%d%d",&n,&k);
    init();
    for(int i=0;i<n-1;i++){
   
        scanf("%d%d",&u,&v);
        addEdge(u,v);
    }
    dfs(1,0);
    printf("%lld\n",dp[1][0]);
    return 0;
}