【树形背包(边)】【调试毒瘤】LuoGu P2015 二叉苹果树

这道题的状态转移方程极其好想,不会可以回家洗洗睡了

dp[now][j]=max(dp[now][j],dp[now][j-k-1]+dp[to][k]+edge[i].val)

但是!!

调试极其毒瘤!

本以为背包背的是边和点差不多,结果发现恶心至极

 1 int DP(int now,int fa)
 2 {
 3     int sum=0;
 4     for(int i=head[now],to;i!=-1;i=edge[i].nxt)
 5     {
 6         to=edge[i].to;
 7         if(to==fa)continue;
 8         leaf=0;
 9         int tt=DP(to,now);
10         sum+=tt;        
11         for(int j=sum;j>=0;j--)
12         {
13             for(int k=0;k<=tt-1;k++)
14             {
15                 if(j>=k+1)dp[now][j]=max(dp[now][j],dp[now][j-k-1]+dp[to][k]+edge[i].val);
16             }
17         }
18     }
19     return sum+1;
20 }

来让我们慢慢分析为什么要这么写,

1.那个sum是什么

  sum返回的其实是点的数量(这样好理解),或者理解成子树的边的个数+1也行,为什么要+1,因为对于叶节点,它下面没有边,返回的不可能是0,只能是1,所以只能加一

2.枚举范围是为什么??

  首先看j的范围,我什么是sum呢?记得sum是什么吗,是子树边,加一,刚好是父节点要选的,所以可以直接就是sum,

  看k的范围,为什么是tt-1,也是因为sum的意义,减1了才是子树的边数量

  那么为什么是j-k-1呢,因为如果你在当前子节点选了k个,同时你也把根节点和子节点的边也选了,所以实际上选的是k+1个边,

  然后j>=k+1就是怕超范围

结束QAQ

上代码

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define N 111
 5 #define _ 0
 6 using namespace std;
 7 int n,q,u,v,w,cnt=1;
 8 int head[N],dp[N][N];
 9 struct star{int to,nxt,val;}edge[N*2];
10 inline void add(int u,int v,int w)
11 {
12     edge[cnt].nxt=head[u];
13     edge[cnt].to=v;
14     edge[cnt].val=w;
15     head[u]=cnt++;    
16 }
17 int DP(int now,int fa)
18 {
19     int sum=0;
20     for(int i=head[now],to;i!=-1;i=edge[i].nxt)
21     {
22         to=edge[i].to;
23         if(to==fa)continue;
24         int tt=DP(to,now);
25         sum+=tt;        
26         for(int j=min(sum,q);j>=0;j--)
27         {
28             for(int k=0;k<=tt-1;k++)
29             {
30                 if(j>=k+1)dp[now][j]=max(dp[now][j],dp[now][j-k-1]+dp[to][k]+edge[i].val);
31             }
32         }
33     }
34     return sum+1;
35 }
36 int main()
37 {
38     memset(head,-1,sizeof(head));
39     scanf("%d%d",&n,&q);
40     for(int i=1;i<n;i++)
41         scanf("%d%d%d",&u,&v,&w),
42         add(u,v,w),add(v,u,w);
43     DP(1,-1);        
44     printf("%d",dp[1][q]);
45     return ~~(0^_^0);
46 }
原文地址:https://www.cnblogs.com/Qin-Wei-Kai/p/10110586.html