DPツリーは、固有の最適化を有する(DP [I] [j]を求め、現在力の要素の数の再帰的列挙を介している私は根ざし選択サブツリーが最大値を選択したj個の要素を有する表します)
(SIZアレイと、現在のノードの子孫の総数を表します。)
1. hdu1561(裸木ナップザック問題に依存)
注SIZアレイuが選択点ノードの数を列挙使用、及び場合逆に、ちょうど01バックパック
複雑一見はO(n ^ 3)は、O(N ^ 2)についての実際です。
#include <iostreamの> する#include <cstdioを> する#include <CStringの> する#include <アルゴリズム> の#include <ベクトル> 使用して 名前空間STD; のconst int型 MAXN = 250 ; ベクター < INT > G [MAXN]; int型DP [MAXN] [ MAXN]; int型[MAXN]ヴァルと、 INT SIZ [MAXN]; int型N-、M; // DP [i] [j]は選択されたI jの要素をルート選択したサブツリーを表すの最大値を有する ボイド DFSを(INT U){ SIZ [U] = 1 ; DP [U] [ 1 ] =;ヴァル[U] のための(int型 I = 0、IはG [U] .sizeを()<; Iは++ ){ int型 V = G [U] [I]、 DFS(V); // SIZ [U] SIZ [V]を含み、バックパック01と^ N 2を与えないプロセスの低い効率でない ため(int型 I = SIZ [U]は、I> = 1 ; I - ){ // ここに01としてこの点が優れている再帰的な点によって、この状況を回避するためにバックパック、 のために(INT J = 1。 ; Jが<= SIZ [V] && IがJ <= M +; J ++){ //を単に回避するために、前記に好き最適V発売から三点を取ることである DP [U]は[iが+ J = MAX(DP [U] [iが+ J]、DP [U] [I] + DP [V] [J])。 // バックとDP値の正面からのみ良好溶液由来の誤差の点jから取ります } } SIZ [U] + = SIZ [V]。 } } int型のmain(){ 一方(のscanf(" %d個の%のD "、&N、&M)=!EOF){ 場合(N == 0 && m個の== 0)破ります。 以下のために(int型 i = 0 ; iが<= N; iは++ ){ ための(int型 J = 0 ; J <= nであり、j ++ ){ DP [I] [J] = 0 ; } G [I] .clear(); } int型トン; 以下のために(int型私= 1 ; iが<= N; iが++ ){ scanf関数(" %D%D "、&T、ヴァル+ i)は、 G [t]は.push_back(I)。 } M ++ 。 DFS(0 )。 printf(" %d個の\ n "、DP [ 0 ] [M])。 } }
2. codeforcesの815C (木DP)
選択したツリー項目は、親子関係を持っている必要がありますが、クーポンの使用と父と息子の関係について、あなたはDPを置くことができないかもしれないクーポンを使用するかどうかを示す、複数の次元の配列を増加させました。
あなただけが、この初期設定をデフォルト値のinfファイルを設定する必要があります。
DP [ U] [ 0] [ 0] = 0;
DP [ U] [ 1] [ 0] = cで[U]。
DP [ U] [ 1] [ 1] = cで[U] -d [U]。
私たちは、列挙の時点でゼロに、この要素を考慮することができます。
#include <cstdioを> する#include <アルゴリズム> の#include <CStringの> する#include <ベクトル> 使用して 名前空間STD; のconst int型 MAXN = 5005 ; INT DPは[MAXN] [MAXN] [ 2 ]; // DP [I] [J ] iがjの要素の最大値をルートとするサブツリー表す ベクトル< INT > G [MAXN]を; // 再び後、このルート要素Iの一次元表現場合、すなわちないクーポンと INT ヴァル[MAXN ]、D [MAXN]; INT SIZ [MAXN]; ボイド DFS(INT U){ SIZ [U] = 1 ; DP [U] [ 1 ] [ 1。] =ヴァル[U]は- D [U]は、 DP [U] [ 1 ] [ 0 ] = ヴァル[U]; DP [U]は[ 0 ] [ 0 ] = 0 ; のために(INT I = 0 ;私は< G [U] .size();私は++ ){ int型 V = G [U] [I]、 DFS(V); // SIZ [U]が含まれていないSIZ [V] のための(int型 I = SIZ [U ]; I> = 0 ; I - ){ // ここで0は処理を取ることではないかもしれない ため(INT J = 0 ; J <= SIZ [V]; J ++ ){ DP [U]は[Iは】Jを+ [0 ] =分(DP [U] [iがjは+] [ 0 ]、DP [U] [I] [ 0 ] + DP [V] [j] [ 0 ])。 DP [U] [iが jは+] [ 1 ] =分(DP [U]は[I jの+] [ 1 ]、DP [U] [I] [ 1 ] +分(DP [V] [j] [ 0 ]、DP [V] [J] [ 1 ]))。 } } SIZ [U] + = SIZ [V]。 } } int型のmain(){ int型N、B。 scanf関数(" %D%dの"、&N、&B)。 scanf関数(" %d個の%のD "、ヴァル+ 1、D +1 ); 以下のために(int型私= 2 ; iが<= N; iが++ ){ int型Tと、 scanf関数(" %D%D%D "、ヴァル+ I、D + I&T)。 G [t]は.push_back(I)。 } のmemset(DP、0x3fを、はsizeof (DP))。 DFS(1 )。 INT ANS = N。 一方(DP [ 1 ] [ANS] [ 1 ]> DP && B [ 1 ] [ANS] [ 0 ]> B){ ANS - 。 //printf( "%D%D \ n"は、DP [1]〜[ANS] [1]、DP [1]〜[ANS] [0])。 } のprintf(" %d個の\ n " 、ANS)。 }