codevs1378 選課 樹形dp

2021-07-23 03:44:17 字數 2866 閱讀 5616

codevs1378 選課

題目描述 description

學校實行學分制。每門的必修課都有固定的學分,同時還必須獲得相應的選修課程學分。學校開設了n(n<300)門的選修課程,每個學生可選課程的數量m是給定的。學生選修了這m門課並考核通過就能獲得相應的學分。

在選修課程中,有些課程可以直接選修,有些課程需要一定的基礎知識,必須在選了其它的一些課程的基礎上才能選修。例如《frontpage》必須在選修了《windows操作基礎》之後才能選修。我們稱《windows操作基礎》是《frontpage》的先修課。每門課的直接先修課最多只有一門。兩門課也可能存在相同的先修課。每門課都有乙個課號,依次為1,2,3,…。 例如:

【詳見】

表中1是2的先修課,2是3、4的先修課。如果要選3,那麼1和2都一定已被選修過。   你的任務是為自己確定乙個選課方案,使得你能得到的學分最多,並且必須滿足先修課優先的原則。假定課程之間不存在時間上的衝突。

輸入描述 input description

輸入檔案的第一行包括兩個整數n、m(中間用乙個空格隔開)其中1≤n≤300,1≤m≤n。

以下n行每行代表一門課。課號依次為1,2,…,n。每行有兩個數(用乙個空格隔開),第乙個數為這門課先修課的課號(若不存在先修課則該項為0),第二個數為這門課的學分。學分是不超過10的正整數。

輸出描述 output description

輸出檔案只有乙個數,實際所選課程的學分總數。

樣例輸入 sample input

7 4

2 2

0 1

0 4

2 1

7 1

7 6

2 2樣例輸出 sample output

13資料範圍及提示 data size & hint

各個測試點1s

樹形動態規劃特點

拿到一道樹規題,我們有以下3個步驟需要執行:

1.判斷是否是一道樹規題:即判斷資料結構是否是一棵樹,然後是否符合動態規劃的要求。如果是,那麼執行以下步驟,如果不是,那麼換台。

2.建樹:通過資料量和題目要求,選擇合適的樹的儲存方式。如果節點數小於5000,那麼我們可以用鄰接矩陣儲存,如果更大可以用鄰接表來儲存(注意邊要開到2*n,因為是雙向的。這是血與淚的教訓)。如果是二叉樹或者是需要多叉轉二叉,那麼我們可以用兩個一維陣列brother,child來儲存(這一點下面會仔細數的)。

3.寫出樹規方程:通過觀察孩子和父親之間的關係建立方程。我們通常認為,樹規的寫法有兩種:

a.根到葉子:不過這種動態規劃在實際的問題中運用的不多。本文只有最後一題提到。

b.葉子到根: 既根的子節點傳遞有用的資訊給根,完後根得出最優解的過程。這類的習題比較的多。

注意:這兩種寫法一般情況下是不能相互轉化的。但是有時可以同時使用具體往後看。

思路:我所學習的第一道樹形動態規劃,我一看是以為這其實是有依賴的揹包問題,但其實不然。因為有依賴的揹包問題只限定於乙個物品只依賴於乙個物品,而沒有間接的依賴關係。有依賴的揹包問題的模型,根本解決不了。所以pass。

1.首先你會發現這其實是一片森林,然後你得把森林轉換成二叉樹。然後進行dp。

2.建樹,森林轉二叉樹,坑了好久才完**生第一次轉二叉樹,附**。

struct node

tree[1001];

void ecs() //建立二叉樹的時候,無非是兩種情況,一種是將其放在起根節點的左兒子上,若根節點的左兒子已有元素,那便放在根結點的左兒子的右兒子上,另一種是放在根節點的右兒子上,若已有元素就放在根節點的右兒子的右兒子上。根節點可以看做是放在tree[0].l上。}}

3.狀態轉移方程:f[i][j]表示以編號為i的結點作為根選j門課所能得到的最大學分。再加上dfs。

f[i][j]=max(max(f[i][j],dfs(tree[i].l,k)+dfs(tree[i].r,j-k-1)+c[i]),dfs(tree[i].r,j));
附**:

#include

#include

using

namespace

std;

int n,m;

int a[2001],c[2001];

int f[1001][1001];

struct node

tree[1001];

void ecs()

}}int dfs(int i,int j)

int main()

這種方法dfs時間效率略差,於是便有了以下另一種dfs方法,先按順序遍歷一遍,維護每乙個狀態的值然後回溯的時候直接加起來就好了。

附**:

#include

#include

using

namespace

std;

int n,m;

int a[2001],c[2001];

int f[1001][1001];

struct node

tree[1001];

void ecs() //建立二叉樹的時候,無非是兩種情況,一種是將其放在起根節點的左兒子上,若根節點的左兒子已有元素,

//那便放在根結點的左兒子的右兒子上,另一種是放在根節點的右兒子上,

//若已有元素就放在根節點的右兒子的右兒子上。根節點可以看做是放在tree[0].l上。

}}void dfs(int x) //優化後的dfs

int main()

codevs1378 選課 樹形DP

學校實行學分制。每門的必修課都有固定的學分,同時還必須獲得相應的選修課程學分。學校開設了n n 300 門的選修課程,每個學生可選課程的數量m是給定的。學生選修了這m門課並考核通過就能獲得相應的學分。在選修課程中,有些課程可以直接選修,有些課程需要一定的基礎知識,必須在選了其它的一些課程的基礎上才能...

code vs 1378 選課(樹形DP)

時間限制 1 s 空間限制 128000 kb 題目等級 鑽石 diamond 題解 檢視執行結果 學校實行學分制。每門的必修課都有固定的學分,同時還必須獲得相應的選修課程學分。學校開設了n n 300 門的選修課程,每個學生可選課程的數量m是給定的。學生選修了這m門課並考核通過就能獲得相應的學分。...

codevs 1378 選課 (樹形dp)

go to the problem 時間限制 1 s 空間限制 128000 kb 學校實行學分制。每門的必修課都有固定的學分,同時還必須獲得相應的選修課程學分。學校開設了n n 300 門的選修課程,每個學生可選課程的數量m是給定的。學生選修了這m門課並考核通過就能獲得相應的學分。在選修課程中,有...