洛谷 P2015 二叉苹果树

目录:

  • 分析:
  • 代码:


分析:

先上个动态转移方程:
f[a][j]=max(f[a][j],f[a][jk1]+f[to][k]+e[i].w)(1jmin(m,king[a]),0kmin(king[to],j1)) f [ a ] [ j ] = m a x ( f [ a ] [ j ] , f [ a ] [ j − k − 1 ] + f [ t o ] [ k ] + e [ i ] . w ) ( 1 ≤ j ≤ m i n ( m , k i n g [ a ] ) , 0 ≤ k ≤ m i n ( k i n g [ t o ] , j − 1 ) )
对于这个方程,内容是很好理解的,king代表以i点为根的树一共有几条边,a代表当前节点,to代表a的一个子节点,现在大家想想就理解了
但对于范围,小编就来解释解释:
j:j代表保留的枝数,因为我们输入时已经限制了最大保留数m,而树a一共只有king[a]条边,所以j肯定小于等于king[a]
k:k代表我们在子树to中砍掉了多少树枝,所以也肯定小于等于king[to],而至于j-1,是因为我们必须保留一个将to和a连接的边


代码:

#include
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
int n=read(),m=read();
int king[101],f[101][101],ls[101],x[101],c=0,w[101];
struct edg{
    int to,next,w;
}e[201];
void add(int a,int b,int www)
{
    e[c].to=b;e[c].w=www;e[c].next=ls[a];ls[a]=c++;
}
void dp(int a,int b)
{
    for(int i=ls[a];~i;i=e[i].next)
    {
        int to=e[i].to;
        if(to==b) continue;
        dp(to,a);
        king[a]+=king[to]+1;
        for(int j=min(m,king[a]);j>=1;--j)
          for(int k=min(king[to],j-1);k>=0;--k)
            f[a][j]=max(f[a][j],f[a][j-k-1]+f[to][k]+e[i].w);
    }
    return;
}
int main()
{     
    memset(ls,-1,sizeof ls);      
    int a,b,xw;
    for(int i=1;i1,0);
    printf("%d",f[1][m]);
    return 0;
}

你可能感兴趣的:(树形dp)