動態規劃 選課(樹形)

2022-07-21 00:03:24 字數 2746 閱讀 4916

問題

描述 description

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

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

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

輸入格式 input format

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

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

輸出格式 output format

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

分析根據題目描述我們可以知道這是個樹形動規問題,但由於乙個點可以有多個兒子,很難寫出方程,所以我們想到將森林轉二叉,之後再去做。

這裡先補充一下多叉轉二叉的知識,其規則是左兒子,有兄弟。這道題是森林,我們只需要虛擬零節點即可。我們要搜尋的根就是f[0].left;

粘個小**

type cc=record

l,r:longint;

end;

var

tree:array[1..1000] of cc;

a:array[1..1000,1..1000] of longint;

m,i,x,y,z,t:longint;

begin

readln(m);

for i:=1 to m do

begin

readln(x,y,z);

a[x,y]:=z;

if tree[x].l=0 then tree[x].l:=y;

t:=tree[x].l;

while(tree[t].r<>0)do t:=tree[t].r;

tree[t].r:=y;

end;

end.

轉化為二叉樹之後,我們很容易就能寫出方程f[i,j]表示以i為根的樹,選了j門課能夠得到的最大學分。

f[i,j]:=max只和當前這門課選不選有關,這是很顯然的,完全根據我們轉換出的二叉樹的定義和題目要求得來。

反思在樹的兒子很多,很難處理時候,我們可以考慮多叉轉二叉,或者森林轉二叉。簡化方程,只和當前節點擊或者不選有關。特別注意,這樣轉的話會加大樹的深度,也就是我們壓棧的次數,資料範圍極大時慎用。

記憶化搜尋是解決樹歸的利器,注意記憶化搜尋的框架,和打法。一定要注意細節。在函式中應有當前狀態是否已知的判斷,邊界條件的處理(注意給陣列賦值),根據方程列舉狀態找最優,最後將求出的最優賦到陣列中再返回值。

code

program liukee;

type lkj=record

l,r,num:longint;

end;

varf:array[0..1000,0..1000] of longint;

tree:array[0..1000] of lkj;

n,m:longint;

procedure init;//讀入資料,多叉轉二叉

vari,x,y,t:longint;

begin

readln(n,m);

for i:=1 to n do

begin

readln(x,tree[i].num);

if tree[x].l=0 then

tree[x].l:=i

else

begin

t:=tree[x].l;

while(tree[t].r<>0) do t:=tree[t].r;

tree[t].r:=i;

end;

end;

end;

function find(i,m:longint):longint;//記憶化搜尋

varj,temp1,temp2:longint;

begin

if f[i,m]<>-1 then exit(f[i,m]);

if(i=0)or(m=0)then

begin

f[i,m]:=0;

exit(0);

end;

temp1:=find(tree[i].r,m);

for j:=0 to m-1 do

begin

temp2:=find(tree[i].l,j)+find(tree[i].r,m-1-j)+tree[i].num;

if temp2>temp1 then temp1:=temp2;

end;

f[i,m]:=temp1;

exit(f[i,m]);

end;

begin

fillchar(f,sizeof(f),$ff);

init;

writeln(find(tree[0].l,m));

end.

選課 樹形動態規劃

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

選課 動態規劃

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

樹形動態規劃

description 有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3 4 1現在這顆樹枝條太多了,需要剪...