解题:USACO12FEB Nearby Cows

树形DP详解与实战
本文深入解析树形动态规划的原理与应用,通过具体实例介绍如何预处理点的子树距离信息,避免重复计算,实现高效求解。文章涵盖核心代码实现与详细步骤说明,适合初学者及进阶者学习。

题面

比较简单的树形dp(递推?)

设$dp[i][j]$表示距离$i$距离为$j$的点的数目,先预处理$g[i][j]$表示点$i$的子树中距离这个点距离为$j$的点的数目(猫老师讲过,用一个栈维护一下就好了),然后再预处理根节点,之后开始考虑dp。

当进入一个儿子时,首先这个儿子对于所有距离$dis$会继承距离父亲$dis-1$的点,然后是它的子树中距离它为$dis$的点,但是这样距离它为$dis-2$的点会被算重复,减掉就好了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=100005,K=22;
 6 int p[N],noww[2*N],goal[2*N];
 7 int num[N],stk[N],pts[N][K],dp[N][K];
 8 int n,k,t1,t2,cnt,top,ans;
 9 void link(int f,int t)
10 {
11     noww[++cnt]=p[f];
12     goal[cnt]=t,p[f]=cnt;
13 }
14 void MARK(int nde,int fth)
15 {
16     stk[++top]=nde;
17     for(int i=0;i<=k;i++)
18         if(top>i) pts[stk[top-i]][i]+=num[nde];
19     for(int i=p[nde];i;i=noww[i])
20         if(goal[i]!=fth) MARK(goal[i],nde);
21     top--;
22 }
23 void DFS(int nde,int fth)
24 {
25     dp[nde][0]=pts[nde][0];
26     for(int i=1;i<=k;i++)
27         if(nde==1) dp[1][i]=pts[1][i];
28         else dp[nde][i]=dp[fth][i-1]-pts[nde][i-2]+pts[nde][i];
29     for(int i=p[nde];i;i=noww[i])
30         if(goal[i]!=fth) DFS(goal[i],nde);
31 }
32 int main()
33 {
34     scanf("%d%d",&n,&k);
35     for(int i=1;i<n;i++)
36     {
37         scanf("%d%d",&t1,&t2);
38         link(t1,t2),link(t2,t1);
39     }
40     for(int i=1;i<=n;i++)
41         scanf("%d",&num[i]);
42     MARK(1,0); DFS(1,0);
43     for(int i=1;i<=n;i++)
44     {
45         ans=0; 
46         for(int j=0;j<=k;j++)
47             ans+=dp[i][j];
48         printf("%d\n",ans);
49     }
50     return 0;
51 }
View Code

 

转载于:https://www.cnblogs.com/ydnhaha/p/9770454.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值