王偉業(yè) 路宇 李曉寒
摘要:貪吃的九頭蛇是樹(shù)形動(dòng)態(tài)規(guī)劃的經(jīng)典問(wèn)題,是基于樹(shù)結(jié)構(gòu)的動(dòng)態(tài)規(guī)劃問(wèn)題。
關(guān)鍵詞:樹(shù)形 動(dòng)態(tài)規(guī)劃
一、問(wèn)題描述
傳說(shuō)中的九頭龍是一種特別貪吃的動(dòng)物。雖然名字叫“九頭龍”,但這只是說(shuō)它出生的時(shí)候有九個(gè)頭,而在成長(zhǎng)的過(guò)程中,它有時(shí)會(huì)長(zhǎng)出很多的新頭,也會(huì)有舊頭因衰老而自己脫落。 有一天,有 M(M≥3) 個(gè)腦袋的九頭龍看到一棵長(zhǎng)有 N 個(gè)果子的果樹(shù),喜出望外,恨不得一口把它全部吃掉。 可是必須照顧到每個(gè)頭,因此它需要把 N 個(gè)果子分成 M 組,每組至少有一個(gè)果子,讓每個(gè)頭吃一組。 這 M 個(gè)腦袋中有一個(gè)最大,稱為“大頭”,是眾頭之首,它要吃掉恰好 K 個(gè)果子,而且 K 個(gè)果子中理所當(dāng)然地應(yīng)該包括唯一的一個(gè)最大的果子。 果子由 N-1 根樹(shù)枝連接起來(lái),由于果樹(shù)是一個(gè)整體,因此可以從任意一個(gè)果子出發(fā)沿著樹(shù)枝“走到”任何一個(gè)其他的果子。對(duì)于每段樹(shù)枝,如果它所連接的兩個(gè)果子需要由不同的頭來(lái)吃掉,那么兩個(gè)頭會(huì)共同把樹(shù)枝弄斷而把果子分開(kāi);如果這兩個(gè)果子是由同一個(gè)頭來(lái)吃掉,那么這個(gè)頭會(huì)懶得把它弄斷而直接把果子連同樹(shù)枝一起吃掉。當(dāng)然,吃樹(shù)枝并不是很舒服的,因此每段樹(shù)枝都有一個(gè)吃下去的“難受值”,而九頭龍的難受值就是所有頭吃掉的樹(shù)枝的“難受值”之和。九頭龍希望它的“難受值”盡量小,你能幫它算算嗎?
二、例題求解
例:果樹(shù)包含 8 個(gè)果子,7 段樹(shù)枝,各段樹(shù)枝的“難受值”標(biāo)記在了樹(shù)枝的旁邊。九頭龍有三個(gè)腦袋,大頭需要吃掉 6 個(gè)果子,其中必須包含最大的果子。
即 N=8 ?,M=3 ,K=6。
首先,判斷問(wèn)題是否有解。判斷是否有解是十分簡(jiǎn)單的。我們只需要看在給每個(gè)小頭分配1個(gè),大頭分配K個(gè)的情況下,所需要的果子的數(shù)量是否大于了果子的總數(shù),即若M+K-1>N,則無(wú)解,此題M+K-1=8=N,故有解。
接下來(lái)就是有解的情況了。
首先我們需要知道,再分配好大頭之后,剩下的果子必然存在一種分配方式,使得九頭龍的難受值不會(huì)再增加??紤]樹(shù)的結(jié)構(gòu),每一條線都連接相鄰兩層的果子,故只需由第一層到最后一層讓小頭依次吃,如果層數(shù)多于小頭數(shù)量,則循環(huán)進(jìn)行。
解決了這個(gè)問(wèn)題之后,我們就只需要考慮大頭了。對(duì)于每一個(gè)果子來(lái)說(shuō),它要么是被大頭吃,要么是不被。于是,我們便可以用樹(shù)形DP來(lái)解決。
設(shè)DP[u][sum][0]表示u結(jié)點(diǎn),它以及它的兒子中,大頭吃了sum個(gè)果子,并且當(dāng)前這個(gè)沒(méi)有被大頭吃。
那么DP[u][sum][1]就是表示u結(jié)點(diǎn),它以及它的兒子中,大頭吃了sum個(gè)果子,并且當(dāng)前這個(gè)被大頭吃了。
可得遞推關(guān)系式:
DP[u][sum][0]=min{sigma{min(DP[v][j][0],DP[v][j][1])}} sigma{j}=sum;
DP[u][sum][1]=min{sigma{min(DP[v][j][0],DP[v][j][1]+len)}} sigma{j}=sum-1;
DP[u][1][1]=DP[u][0][0]=0;
問(wèn)題歸結(jié)于求解DP[1][K][1]
DP[8][0][0]=0 ? ? DP[8][1][1]=0 ? ? DP[7][0][0]=0 ? ? DP[7][1][1]=0
DP[6][0][0]=0 ? ? DP[6][1][1]=0 ? ? DP[5][0][0]=0 ? ? DP[5][1][1]=0
DP[4][0][0]=0 ? ? DP[4][1][0]=0 ? ? DP[4][2][0]=0 ? ? DP[4][1][1]=0
DP[4][2][1]=5 ? ? DP[4][3][1]=20 ? ?DP[3][0][0]=0 ? ? DP[3][1][1]=0
DP[2][0][0]=0 ? ? DP[2][1][1]=1 ? ? DP[2][2][0]=0 ? ? DP[2][2][1]=10
DP[2][1][0]=0 ? ? DP[2][3][1]=22
最終目標(biāo):
DP[1][6][1]=min{55,42,13,24, 37}=13(分別對(duì)應(yīng)3 1 1;3 0 2;2 1 2;2 0 3;1 1 3)
即取2 1 2,大頭吃1 3 5 6 7 8,得解。
三、小結(jié)
貪吃的九頭龍問(wèn)題是典型的樹(shù)形動(dòng)態(tài)規(guī)劃問(wèn)題,在樹(shù)結(jié)構(gòu)上進(jìn)行動(dòng)態(tài)規(guī)劃,求解時(shí)關(guān)鍵是找出遞推關(guān)系,逐步計(jì)算,最終即可得到答案。