學生要在n門課程中選m門課程,每門課程最多依賴於一門前置課程(可以有多門課程沒有前置課程),問能獲得的最大學分是多少。(1<=m<=n<300)
顯然,每門課程依賴至多一門,有課程可以沒有依賴,所以這是乙個多叉樹森林。
森林不太好處理,所以我們可以給森林加個虛擬根節點#0,讓每棵樹的根節點連到這個總結點上。問題即轉化為在這個多叉樹#0上選m門課程的最大學分,自然而然地,我們得到了dp狀態dpi
,j
dp_dp
i,j
,即在i子樹上選擇j門課程可以得到的最大學分。
按照二叉樹的思維來想,i子樹的j門課程可以分配給它的子樹們,即
d p[
i][j
]=∑d
p[so
ni][
ki]+
pnt[
i],w
here
∑ki=
j−
1dp[i][j] = \sum dp[son_i][k_i] + pnt[i]\ , \ where \ \sum k_i = j - 1
dp[i][
j]=∑
dp[s
oni
][ki
]+p
nt[i
],wh
ere∑
ki=
j−1但顯然,由於i子樹可能有很多兒子,這樣排列組合下來複雜度很高,所以這樣不可取。當然,多叉樹直接算的辦法還是有的,但我目前沒有完全理解(確實不好理解)。事實上,我們可以曲線救國。既然二叉樹的辦法套在多叉樹上不好用,那我們就乾脆把多叉樹變成二叉樹——孩子兄弟樹。
孩子兄弟樹,即左子樹是孩子,右子樹是兄弟。顯然,選i子樹的孩子課程就得選父親課程,但是選兄弟課程就不會受i子樹的影響,因此dp狀態dpi
,j
dp_dp
i,j
,即在i子樹(i和i的孩子、i的兄弟)上選擇j門課程可以得到的最大學分,轉移式為
d p[
i][j
]=
dp[i][j] = \begin dp[bro_i][j]\\ max \ \end
dp[i][
j]=
對應上式的情況分別為
不選課程i,只選i兄弟的課程
選i課程, 再選 i的孩子課程和兄弟課程共計j-1門
此處採取了dfs的方式保證了遍歷順序,準確的講是記憶化搜尋。
# include
# include
# include
# include
using
namespace std;
const
int maxn =
310;
int fa[maxn]
, son[maxn]
, bro[maxn]
, val[maxn]
;//fa是不必要的
int dp[maxn]
[maxn]
;inline
void
add(
int f,
int s)
intdfs
(int i,
int j)
intmain()
printf
("%d\n"
,dfs(0
, m +1)
);system
("pause");
return0;
}
(多叉樹轉二叉樹,大讚!)
(分析了兩種方法,多叉/二叉)
(多叉樹法,分析得不錯,但多叉有個地方我理解不了~)
選課 P2014 樹形DP
在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有n門功課,每門課有個學分,每門課有一門或沒有直接先修課 若課程a是課程b的先修課即只有學完了課程a,才能學習課程b 乙個學生要從這些課程裡選擇m門...
P2014 選課(樹形DP)
傳送門 樹形dp入門題。這類題目被稱為揹包樹形dp,又稱有樹形依賴的揹包問題。雖說是入門題,但第一次寫並不是很順利,網上的解法都是二維的,但我只會先用高維做再轉成低維的,搞的就很難受。三維解法,思路見注釋 include include include define maxn 305 using n...
DP 樹形DP luogu2015 二叉蘋果樹
一棵二叉蘋果樹,邊上結了蘋果需要砍去一些邊,求保留q條邊時最多能保留多少蘋果。1 n,q 100 2 5 3 4 1題目保證了原始蘋果樹有分叉則必為二叉,且1為root注意輸入時父子順序是不確定的,所以需要做處理 定義d pi j dp dp i,j 表示編號為i的子樹在保留j條邊的情況下獲得的最大...