選課 動態規劃

2021-08-08 17:30:13 字數 1841 閱讀 6788

洛谷p2014

在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有n門功課,每門課有個學分,每門課有一門或沒有直接先修課(若課程a是課程b的先修課即只有學完了課程a,才能學習課程b)。乙個學生要從這些課程裡選擇m門課程學習,問他能獲得的最大學分是多少?

輸入輸出格式

輸入格式:

第一行有兩個整數n,m用空格隔開。(1<=n<=300,1<=m<=300)

接下來的n行,第i+1行包含兩個整數ki和si, ki表示第i門課的直接先修課,si表示第i門課的學分。若ki=0表示沒有直接先修課(1<=ki<=n, 1<=si<=20)。

輸出格式:

只有一行,選m門課程的最大得分。

輸入輸出樣例

輸入樣例#1:

7 4

2 2

0 1

0 4

2 1

7 1

7 6

2 2輸出樣例#1:

13題目中提到每門課的直接先修課最多只有一門,將每門課的先修課與其相連,將會構成一顆或者多顆樹。為此我們可以建立乙個 0 號節點,將所有樹的根節點都連向 0 號節點。0 號節點的學分為 0,並且允許選修的課數量要自加一。

將森林拼接成一棵樹之後我們就需要對這一顆樹進行樹上的動態規劃了。

考慮樹上的每乙個節點:這個節點可能是乙個或者多個節點的父節點(先修課),也有可能沒有。用 f[i][j] 表示對於節點 i , 一共選擇 j 門課所能得到的最大學分(j 門科目中包括他本身)。選擇他的所有子節點的前提是一定要選擇這個節點,所 f[i][1] 一定等於 i 節點的權值(學分)

按照一定的順序遍歷 i 節點的所有子節點。當遍歷到 x 節點的時候,我們假設已經得到了所有 f[x][k] 的值。由於 f[i][k] 中是沒有 x 節點及其子樹的權值的,所以可以通過 x 節點來更新 i 節點的 f 陣列。即 f[i][k] = max(f[i][k], f[i][k - p] + f[x][p]) (1 ≤ k ≤ m , 0 ≤ p < k)

p < k 的原因是當 p = k 的時候 f[i][k - p] 中 k - p 的值等於 0,這說明 i 這個節點無法被選擇到,由於 i 是 x 節點的先修課,不選擇 i 節點便無法選擇 x 節點,所以應滿足 p < k

在列舉 k 的時候需要注意:由於 f[i][k] 由 f[i][k - p] 更新得到,那麼就需要保證更新 f[i][k] 的時候 f[i][k - p] 沒有被更新,由於 p 是乙個正整數,所以我們倒序列舉 k 即可

#include 

#include

#include

using

namespace

std;

int n, m;

int score[305], fa[305];

bool vis[305];

int f[305][305];

int head[305], edge_len;

struct edge edges[605];

void add(int from, int to)

void dfs(int x)

}int main()

m++; // 由於 0 號節點的參與,m 需要自加1

dfs(0);//搜尋 0 號節點

cout

<< f[0][m];

return

0;}

選課 樹形動態規劃

題目大意 在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有n門功課,每門課有個學分,每門課有一門或沒有直接先修課 若課程a是課程b的先修課即只有學完了課程a,才能學習課程b 乙個學生要從這些課程...

動態規劃 選課(樹形)

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

HDU 2079 選課時間 動態規劃

題目傳送門 這個題目乍一看像是個多重揹包問題,仔細一想還真是個多重揹包問題,只是沒有權值而已。這樣,我們的狀態就要改變了。求什麼就設什麼 狀態 dp i 表示已經組合好i個學分的組合數 刻畫子結構特徵 新的高學分的組合數都可以轉化為低學分的和。舉個栗子 目標4學分 2種學分種類 1學分 2門 2學分...