$ Luogu $ $ $ P2015バイナリリンゴの木

リンク

背景

\(Luogu \) \(P1122 / Codevs5565 \)

問題の意味

所与\(N- \)をノードに\(1 \)ツリーのルートノードとしてドット\(N-1 \)側と重量\((X_I、Y_I、W_i)\) 枝の一部カットしようとしているの後に左\(Q \)最大側と右端を。

ソリューション

また、それは木である\(DP \)テンプレート。または演習。
ツリーはバイナリツリーですので、美しい自然があります:サブ木の枝の予約内の樹木は(これはあなたをでたらめされていない)サブツリーによって周りに取得することができます。
問題の意味を考慮すると、切断された分岐の一部、変換を左\(Qが\)すなわち左端\(Q + 1 \)ポイントを、ルートを含まなければなりません。
したがって、セットすることができる\(F_ {X、I} \) で表される(X \)\ノードのサブツリー根付い左(I \)\極大点とエッジの重み。
今回はそれが変換のトピックを検討し続けなければなりません。ルートは必須であるため、そう\(N-1 \)辺が残りに変換することができる\(N-1 \)の重みポイント(親の辺の重みに各点)。右側はそうと、最大の最大のポイントと右になりました。
幸い、その後転送される:レッツノード\(X \)左息子\(L_x \) 右の子である(\ r_x)\次に、\(F_ {X、I} = \ MAX_ \制限{ Jは\ [0 ,. 1-I]は} \ {{L_x F_は、F_ {+} Jをr_x ,. 1-I-J} \} + val_x \)\(l_x \)\(r_x \)
発見のための方法は、下記を参照してください(トリック\)\それを。

騙す

所与\(N-1 \)条無向エッジ\(N(N \ leqslant 3 \回10 ^ 3)\) 左及び右の子ノードを発見するためのポイント二分木のルート方法:
隣接行列を確立し、これ保存する\(INT \)形式、\(G_ {X、Y} \)格納されている((X、Y)\ \ ) 右側の。
再帰的に上から下に、ルートからのビルドを開始しました。
各再帰へカレントノード\(Xは、\)ときに横断される\(N- \)ノードは、最初のノードとしての右側を見つけなければならない\(L_x \) 次いで、再帰処理ノード。直接ループを出た後に返すことができます。探している(r_x \)\再反復するために注意\(N \)ノード、ノードとしてそれの最初の右側有する見つける(r_xを\)\次いで再帰ノードを処理します。

ディテール

2つの境界注:\(F_ {X、0} \)選択される基を表す(\ 0 \) 答えが結合されているノード(\ 0)\ ; \ (L_x = 0 \)\(r_x = 0 \)その\(x \)サブツリーのリーフノードを選択することができない)、それ自体に直接戻り正しい値。

コード

\(ビュー\) \(コード\)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int ret=0,f=1;
    char ch=getchar();
    while('9'<ch||ch<'0')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while('0'<=ch&&ch<='9')
    {
        ret=(ret<<1)+(ret<<3)+ch-'0';
        ch=getchar();
    }
    return ret*f;
}
int n,q,x,y,w,g[105][105],val[105],l[105],r[105],f[105][105];
void make_tree(int x)
{
    for(register int i=1;i<=n;i++)
    {
        if(g[x][i]||!g[x][i])
        {
            val[i]=g[x][i];
            g[x][i]=-1;
            g[i][x]=-1;
            l[x]=i;
            make_tree(i);
            break;
        }
    }
    for(register int i=1;i<=n;i++)
    {
        if(g[x][i]||!g[x][i])
        {
            val[i]=g[x][i];
            g[x][i]=-1;
            g[i][x]=-1;
            r[x]=i;
            make_tree(i);
            break;
        }
    }
}
int dp(int x,int cnt)
{
    if(!cnt)
        return 0;
    if((!l[x])&&(!r[x]))
        return val[x];
    if(f[x][cnt])
        return f[x][cnt];
    for(register int i=0;i<cnt;i++)
    {
        f[x][cnt]=max(f[x][cnt],dp(l[x],i)+dp(r[x],cnt-1-i)+val[x]);
    }
    return f[x][cnt];
}
int main()
{
    n=read();
    q=read();
    memset(g,-1,sizeof(g));
    for(register int i=1;i<n;i++)
    {
        x=read();
        y=read();
        w=read();
        g[x][y]=w;
        g[y][x]=w;
    }
    make_tree(1);
    printf("%d\n",dp(1,q+1));
    return 0;
}

おすすめ

転載: www.cnblogs.com/Peter0701/p/11838826.html