樹形揹包總結

2021-09-27 09:10:08 字數 3097 閱讀 3484

目錄

2、有物品大小:

3、物品大小為1,有k的限制。

二、dfs序上dp:

例題1例題2

例題3總結下:

樹形揹包,就是說,在樹上選乙個包含根的連通塊,或揹包存在依賴關係(選父才能選子),或者需要知道每個點的子樹中選了多少……

通常,我們有兩種方法:

我們設\(dp(i,j)\)表示在i的子節點中選j個的狀態。

在轉移時,先dfs子節點,然後依次把子節點合併,每次合併2個。

即列舉\(a,b\),用\(dp(i,a)\)和\(dp(son,b)\)組合為\(f(a+b)\),每次合併後,把f賦給dp。

下面分析時間複雜度:

void tree_dp(int p)

}

時間複雜度為\(o(n^2)\)。

考慮那個二重迴圈,可以看做分別列舉兩棵子樹的每個點。可以發現,點對\((u,v)\),只會在\(tree_dp(lca(u,v))\)處被考慮到,所以複雜度是\(o(n^2)\)。

這個複雜度我也不清楚,可以卡到\(o(n^3)\),但是,在資料隨機時是能跑過8000,1s的。

void dfs(int u, int fu) 

for (int i = fr[u]; i != -1; i = ne[i])

}si += rt;

sz[u] = si + 1;

}

這個演算法,最初覺得是\(o(nk^2)\)的,實際上是\(o(nk)\)的。

根據正常樹形揹包的複雜度\(o(n^2)\),小於等於k的最多產生\(n/k*k^2\)的複雜度。

大於k與大於k的合併一次,被合併的就增加k,最多n/k次,最多產生\(n/k*k^2\)的複雜度。

大於k的與小於等於k的合併時,每個小於等於k的最多被合併一次,所以是\(n*s_1+n*s_2+...+n*s_m\),也是\(nk\)。

還有一種理解:

把樹按照dfs序變為序列。

然後,在子樹中列舉取x個,可以理解為取dfs序的前(後)x個。

而合併時,認為一棵子樹取後x個,另一棵取前y個。\((x+y\leq k)\)。這可以合併為長x+y的區間。

這其實就是長度不大於k的子串,最多有nk個。

但是,因為有取0個的情況,所以實際做題時,大約有2的常數。但那個常數就忽略了可以。

按照dfs序考慮:

我們設\(dp(i,j)\)表示考慮到第i個,剩餘容量為j的狀態:

有兩種轉移:

1、不選i,那麼i的子樹都不能選,轉移到\(dp(i+size_i,j)\)。

2、選i,那麼按照dfs序考慮下乙個,轉移到\(dp(i+1,j-w)+v\)。

正確性顯然。

(不是我的)

void dfs(int u)

cost[++tot]=temp[u];

f[tot]=tmp;

}int main()

dfs(0);

for(int i=1;i<=m;i++)

}printf("%d\n",dp[m][n]);

}

這個比較顯然,n個點,m的容量限制(沒有則m=n),狀態有\(nm\)個,轉移代價為\(o(1)\),複雜度為\(o(nm)\)。

而且,這種方法更好些,且常數更小。

題目描述

金明今天很開心,家裡購置的新房就要領鑰匙了,新房裡有一間金明自己與用的很寬敞的房間。更讓他高興的是,媽媽昨天對他說:「你的房間需要購買哪些物品,怎麼布置,你說了算,只要丌超過 n 元錢就行」。今天一早,金明就開始做預算了,他把想買的物品分為兩類:主件不附件,附件是從屬於某個件的,下表就是一些主件不附件的例子:

主件 附件

電腦 印表機,掃瞄器

書櫃 圖書

書桌 檯燈,文具

工作椅 無

如果要買歸類為附件的物品,必須先買該附件所屬的件。每個主件可以有很多個附件。附件可能有從屬於自己的附件。金明想買的東西很多,肯定會超過媽媽限定的 n 元。於是,他把每件物品規定了乙個重要度,分為 5 等:用整數 1−5 表示,第 5 等最重要。他還從網際網路上查到了每件物品的**(都是在10 元以內)。他希望在不超過 n 元(可以等於 n 元)的前提下,使每件物品的**不重要度的乘積的總和最大。 設第 j 件物品的**為 v[j] ,重要度為 w[j] ,共選中了 k 件物品,編號依次為 j1,j2,…,jk,則所求的總和為: v[j1]×w[j1]+v[j2]×w[j2]+…+v[jk]×w[jk] 請你幫助金明設計乙個滿足要求的購物單。

輸入格式

第 1 行,為兩個正整數,用乙個空格隔開:

n,m (其中 n(<8000) 表示總錢數, m(< 8000) 為希望購買物品的個數。) 從第 2 行到第 m+1 行,第 j 行給出了編號為 j−1的物品的基本資料,每行有 3 個非負整數::v,p,q(其中 v 表示該物品的**( v< 10),p表示該物品的重要度( 1−5 ), q 表示該物品是主件還是附件。如果 q=0,表示該物品為主件,如果 q>0 ,表示該物品為附件, q 是所屬件的編號(q< j-1))

輸出格式

乙個正整數,為丌超過總錢數的物品的**不重要度乘積的總和的最大值。

這個,是顯然的樹型揹包。

如果用方法1,則由於物品大小的影響,可以卡到\(o(nm^2)\)。

但是,方法二就是\(o(nm)\)的,很快,還好寫。

(差距很大)。

[jsoi2018]潛入行動

這題,由於我要知道父子關係的資訊(例如:父節點是否選擇等),所以方法二便不能使用。

[sdoi2017]蘋果樹

這題有些像例1,只不過物品有多個,轉成dfs序後,單調佇列優化即可,複雜度\(o(nk)\)。如果方法1至少要\(o(nk^2)\)。

方法一:

可以知道每個點的確切情況,可以與普通的樹型dp結合使用(因為畢竟是在樹上)。

但是,複雜度較高(因為合併揹包很慢)。

方法二:

複雜度較低(因為不需要合併揹包,相當於依次新增)。

但是,不能知道每個點的確切情況(因為是在序列上),有些題不能使用。

樹形揹包總結

目錄2 有物品大小 3 物品大小為1,有k的限制。二 dfs序上dp 例題1例題2 例題3例題4 總結下樹形揹包,就是說,在樹上選乙個包含根的連通塊,或揹包存在依賴關係 選父才能選子 或者需要知道每個點的子樹中選了多少 通常,我們有兩種方法 我們設 dp i,j 表示在i的子節點中選j個的狀態。在轉...

樹形依賴揹包

問題大意 給出一棵樹,根節點為1,每個點有毒素和收穫。要求毒素不超過給定值的情況下使收穫最大。乙個點的父親節點被選取後這個點才能被選取。首先弄出dfs序,也記錄下每個點其子樹及自身的大小。每個點都能夠被選或不選,如果選了才會考慮它子樹。設f i j 表示dfs序上第i位上的點在其子樹及自身上選取了毒...

樹形揹包DP

include using namespace std const int n 310,m n 2 int h n ne m v m idx int w n int dp n n int n,m void add int a,int b void dfs int u for int j m j 0 ...