洛谷樹形dp複習

2021-10-25 05:21:14 字數 4362 閱讀 3440

明顯是樹上揹包問題,選與不選,保留的樹枝為體積,每個樹枝的蘋果樹目為價值

f [ i ] [ j ] 表示在 i 節點時,留下了 j 條樹枝時得到的最多蘋果數量

模板列舉孩子節點

·····搜尋更新孩子節點資訊

·····列舉 i 點樹枝數量

············列舉孩子節點所擁有樹枝數量

··················狀態轉移方程

狀態轉移方程:

f [ u ] [ j ] = max ( f [ u ] [ j ] , f [ u ] [ j - k ] + f [ v ] [ k ] )

記得初始化

#include

using

namespace std;

struct edge

e[105];

int fa[

105]

,n,m,cnt,head[

105]

,f[105][

3000050];

void

add(

int u,

int v)

void

dfs(

int u)

}int

main()

for(

int i=

1;i<=n;i++)if

(!fa[i]

)return0;

}

更上題差不多,樹形揹包板子題,要注意當我們規定所有樹的根統一為0,所選總科目應該為m+1,0節點的科目沒有的分,所以不影響答案

#include

using

namespace std;

struct edge

e[305];

int cnt,f[

305]

[6005

],head[

305]

,n,m;

intread()

while

(isdigit

(ch)

)return x*f;

}void

add(

int u,

int v)

void

dfs(

int u)

}int

main()

dfs(0)

;//約定以0為根進行樹上dp

printf

("%d"

,f[0

][m+1]

);return0;

}

類似的樹形揹包

f [ i ] [ j ] 表示在 i 節點擊擇 j 個人時的最大利潤

初始化:葉子節點 f [ i ] [ 1 ] = val [ i ]

接著就是純真無邪的樹上揹包了。

結果t4個點,對於這個題,我們可以:

!!!減掉無用轉移!!!

對於每個節點,它並不是能夠選取到所有的人(因為它子樹的葉子節點並不一定會包括所有的葉子節點),所以說我們在搜尋所有的子樹時,都應該返回該子樹所包含的葉子節點,然後對 j 進行優化列舉,減少轉移次數,然後ac

#include

#define rg register

using

namespace std;

const

int minn=

-1e7

;struct edge

e[10105];

int cnt,n,m,val[

3005

],f[

3005][

3005

],head[

3005];

inline

intread()

while

(isdigit

(ch)

)return x*f;

}inline

void

add(

int u,

int v,

int w)

inline

intdfs

(int u)

}return sum+

(val[u]?1

:0);

}int

main()

}for

(rg int i=

1;i<=n;i++

)for

(rg int j=

1;j<=m;j++

) f[i]

[j]=minn;

for(rg int i=n-m+

1;i<=n;i++

) f[i][1

]=val[i]

=read()

;dfs(1

);int l=

1,r=m;

while

(l<=r)

//小優化

if(f[1]

[r]>=0)

printf

("%d"

,r);

else

printf

("%d",0

);return0;

}

記得補

#include

using

namespace std;

const

int inf=

1e8;

struct edge

e[160];

int n,p,cnt,root;

int f[

155]

[155

],head[

155]

,a[155];

bool bj[

155]

;void

add(

int u,

int v)

intdp

(int x)

return sum;

}int

main()

memset

(f,0x3f

,sizeof

(f))

;for

(int i=

1;i<=n;i++)dp

(root)

;int ans=f[root]

[p];

for(

int i=

1;i<=n;i++)if

(f[i]

[p][p]+1;

printf

("%d"

,ans)

;return0;

}

題目的意思是,小偷要從外面進到美術館,偷完東西後再出美術館,所以一條邊坑定是要走兩次的(來回),而警察來了的時候就判定為被抓到,所以當小偷剛好花費 s 時間時,並不能作為最優答案輸出(坑)

這一道題主要是建邊,以遞迴的形式建邊,根節點為1,因為題目性質,所以乙個點度數只為0或2,保證了該美術館就是乙個二叉樹,

然後就可以按照題目的意思來儲存樹

樹的左孩子為 i < < 1,右孩子為 i < < 1 | 1

所以接下來dp的時候就應該從1出發

f [ i ] [ j ] 表示在 i 節點剩餘 j 分鐘 能偷到的畫的最大數量

注意事項:

s–存邊時直接將邊長<<1(來回走)

dp邊界,當沒有時間或者 節點i 所剩時間j已經被更新過時,可以直接結束dp

dp特判:如果該節點有畫,那麼就花所剩餘的時間偷畫(在i節點偷到畫的數量一定小於等於該節點畫的數量)

dp轉移方程:

列舉i點左子樹所剩餘的時間 j

(為保證能逃出去,j < = time - edge [ i ] )

f [ i ] [ j ] = max ( f [ i ] [ j ] , f [ i <<1] [ j ] , f [ i<<1|1 ] [ time - edge [ i ] - j ](應為要給自己逃跑的時間,所以右子樹所給的時間要再減去這條道路的時間)

#include

using

namespace std;

//第i個展室,共花j分鐘,

int s,f[

1005][

6005

],w[

1005

],edge[

1005];

bool bj[

1005];

void

dfs(

int u)

}intdp(

int u,

int time)

return f[u]

[time];}

intmain()

洛谷2014 選課(樹形DP 樹形揹包問題

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

洛谷luogu P3360 偷天換日(樹形DP)

給乙個有根樹,有邊權,葉子節點有畫可以偷,偷畫和經過邊需要時間,給定n時間,最多可以偷多少價值的畫。這奇怪的資料格式真是給跪了,葉子節點可以揹包,非葉子節點怎麼辦呢?暴力列舉!include include include include include include include define...

洛谷P2014 選課 樹形dp

給出n 300 n leq300 n 30 0個結點,每個結點都有乙個權值,然後一些結點必須只有選了前驅結點這個結點才可以被選。現在最多選m 300 m leq300 m 30 0個結點,求最大權值。實際上這個是乙個森林,但是通過設定乙個權值為0 00的虛點0 00,把所有的沒有前驅的點全部連到這個...