vijos1144 小胖守皇宮《樹形dp

2022-05-07 10:45:05 字數 2418 閱讀 3848

woc我竟然a了,這道經典的樹形dp或者說是樹形dp的入門題我終於過了,雖然之前做過一些樹形dp的題,但是這題開始還是一臉懵逼,dp方程如何定義都知道,但是不懂轉移啊,這就有點傷了。。

dp方程定義dp[i][1]節點i 選自己

dp[i][2]節點i選自己的兒子==不選自己和父親

dp[i][3]節點i選自己的父親==不選自己選父親

然後就是轉移了。。畢竟是基礎題嘛,所以轉移也不難

轉移的時候我們是直接遞迴到葉節點然後再做前面的。。所以我們不用考慮父節點的狀態

dp[i][1]選自己的時候,兒子節點就有兩種方式,選兒子自己,或者選兒子的父親dp[i][1]+=min(dp[son][1],dp[son][3]);

dp[i][2]選兒子時 ,兒子就選或不選兩個方式,但是如果一旦所有的兒子都是不選了,我們就要找乙個最小的兒子樹的值在最後加上,

dp[i][2]+=min(dp[son][1],dp[son][2])如果全部選了2,就要在結尾加上dp[i][2]+=min(dp[son][1]-dp[son][2])

至於為啥加這個,就是這道題唯一有點思考難度的地方了,因為你是要加最小的兒子選乙個的值,所以找到最小,比如時第s2個兒子,之前已經加了dp[s2][2],所以最後的時候是加上dp[s2][1]-dp[s2][2],相當於把之前的那個dp[s2][2]抵消了,就不會加重複

dp[i][3]選父親時,因為我們是從子往父推,所以不從父親轉移,就考慮這時候的兒子節點,兒子節點**就是兒子自己放和兒子的兒子放

dp[i][3]+=min(dp[son][1],dp[son][2]);

好吧這就是這道題的全部了,最後只需要輸出根節點的選自己和選兒子方案的最小值就可,因為根沒有父親。。。

儲存這個關係的方式有兩種,一種是鍊錶,一種是多叉樹轉二叉樹,

兩種方式的不同點在於鍊錶是雙向的,然後重新建樹,預設1為根節點

而多叉樹轉二叉樹是以題目給的關係建樹,以沒有父親的點為根

鍊錶:

1 #include2 #include3 #include4 #include5 #include6 #include7 #include8

#define maxn 1505

9using

namespace

std;

1011

int f[maxn][4

],n;

12struct

edgee[maxn*10

];15

inta[maxn],head[maxn],vis[maxn],tot;

1617

void adde(int u,int

v)23

24void work(int

x)else

38 f[x][3]+=min(f[v][1],f[v][2

]);39}40

if(p==0)f[x][2]+=s;41}

4243

intmain()55}

56 vis[1]=1;work(1

);57 printf("

%d",min(f[1][1],f[1][2

]));

58 }

view code

多叉樹轉二叉樹

1 #include2 #include3 #include4 #include5 #include6 #include7 #include8

#define maxn 3005

9using

namespace

std;

1011

intn,m,a[maxn],root;

12int f[maxn][5

],vis[maxn];

13int

lson[maxn],rson[maxn],fa[maxn];

1415

void work(int

x)16

else f[x][2]+=f[i][1],p=1

;24 f[x][1]+=min(f[i][3],f[i][1

]);25 f[x][3]+=min(f[i][1],f[i][2

]);26}27

if(p==0)f[x][2]+=s;28}

2930

intmain()

3146 rson[now]=s;47}

48}49}

50for(int i=1;i<=n;i++)

51if(fa[i]==0)work(i),root=i;

52 printf("

%d",min(f[root][1],f[root][2

]));

53 }

view code

提醒一點,多叉樹轉二叉樹需要在執行dp之前跑個o(n)找到根節點

裝箱問題 vijos

有乙個箱子容量為v 正整數,o v 20000 同時有n個物品 o n 30 每個物品有乙個體積 正整數 要求從 n 個物品中,任取若千個裝入箱內,使箱子的剩餘空間為最小。第一行,乙個整數,表示箱子容量 第二行,乙個整數,表示有n個物品 接下來n行,分別表示這n個物品的各自體積。乙個整數,表示箱子剩...

vijos 積木城堡

恰似今天更了七章 我該怎麼辦 看上去好像只能瘋狂寫揹包啦 他們說周四化學通練,我好慌 描述 第一行是乙個整數n n 100 表示一共有幾座城堡。以下n行每行是一系列非負整數,用乙個空格分隔,按從下往上的順序依次給出一座城堡中所有積木的稜長。用 1結束。一座城堡中的積木不超過100塊,每塊積木的稜長不...

Vijos 河蟹王國

河蟹王國有一位河蟹國王,他的名字叫羊駝。河蟹王國富饒安定,人們和諧相處。有一天,羊駝國王心血來潮,想在一部分人中挑出最和諧的人。於是,羊駝國王將他的子民排成了一列 b汗 好長呀 每個人都有乙個初始的和諧值。羊駝國王每次會選擇乙個區間 l,r 這個區間中和諧值最大的人就是國王選出的人。而且,在某一時間...