NOI2002 貪吃的九頭龍

2022-05-03 11:45:21 字數 3421 閱讀 7839

p2940貪吃的九頭龍

貪吃的九頭龍(dragon.pas/c/cpp) 

【問題描述】 

傳說中的九頭龍是一種特別貪吃的動物。雖然名字叫「九頭龍」,但這只是說它出生的時候有九個頭,而在成長的過程中,它有時會長出很多的新頭,頭的總數會遠大於九,當然也會有舊頭因衰老而自己脫落。 

有一天,有m個腦袋的九頭龍看到一棵長有n個果子的果樹,喜出望外,恨不得一口把它全部吃掉。可是必須照顧到每個頭,因此它需要把n個果子分成m組,每組至少有乙個果子,讓每個頭吃一組。 

這m個腦袋中有乙個最大,稱為「大頭」,是眾頭之首,它要吃掉恰好k個果子,而且k個果子中理所當然地應該包括唯一的乙個最大的果子。果子由n-1根樹枝連線起來,由於果樹是乙個整體,因此可以從任意乙個果子出發沿著樹枝「走到」任何乙個其他的果子。 

對於每段樹枝,如果它所連線的兩個果子需要由不同的頭來吃掉,那麼兩個頭會共同把樹枝弄斷而把果子分開;如果這兩個果子是由同乙個頭來吃掉,那麼這個頭會懶得把它弄斷而直接把果子連同樹枝一起吃掉。當然,吃樹枝並不是很舒服的,因此每段樹枝都有乙個吃下去的「難受值」,而九頭龍的難受值就是所有頭吃掉的樹枝的「難受值」之和。 

九頭龍希望它的「難受值」盡量小,你能幫它算算嗎? 

例如圖1所示的例子中,果樹包含8個果子,7段樹枝,各段樹枝的「難受值」標記在了樹枝的旁邊。九頭龍有兩個腦袋,大頭需要吃掉4個果子,其中必須包含最大的果子。即n=8,m=2,k=4: 

輸入檔案dragon.in的第1行包含三個整數n (1

輸出檔案dragon.out僅有一行,包含乙個整數,表示在滿足「大頭」的要求的前提下,九頭龍的難受值的最小值。如果無法滿足要求,輸出-1。

8 2 4 

1 2 20 

1 3 4 

1 4 13 

2 5 10 

2 6 12 

3 7 15 

3 8 5

4
該樣例對應於題目描述中的例子。

前言:

分析:

題目簡述:

將一棵樹中的節點染成m種顏色,每個節點有且只有一種顏色,在滿足以下條件下使得兩端顏色相同的邊的權值和最小,所有邊權均非負。

(1)必須有k個1號顏色的點;

(2)1號節點必須是1號顏色;

(3)每種顏色必須至少有乙個節點。如無解,輸-1。

無解的情況很明顯,當且僅當n-k

考慮用動態規劃來解決。

如果以一棵子樹作為乙個子結構,分析需要考慮的狀態:

(1)根節點的顏色。

(2)1號顏色的個數。

(3)樹中顏色的分配情況,如何保證每種顏色都有節點。

初步分析可以得到一種四維的狀態:

f[i][j][k][w],表示在以i為根的子樹中,有j個1號節點,根染k號顏色,樹中已有的顏色用w表示(w是乙個二進位制數)的狀態下最小的權值和。

首先,這個方程用到了狀態壓縮w,因此對於本題300的資料範圍是不現實的,需要繼續思考。

假設這樣乙個問題,仍然是對樹染色,可以任意染色,那麼只要2種顏色,就可以保證任意一條邊兩端的顏色不同,聯想到這道題,因為1號顏色比較特殊,因此單獨處理,而餘下的顏色如果大於等於2種,那麼無論1號顏色如何染色,都可以保證一條邊兩邊不會出現相同的非1號顏色的情況,換言之,如果m>=3,對答案有貢獻的只有1號顏色節點之間的邊。這樣當m>=3時,可以直接按3處理,這樣狀態壓縮是可以承受的。既然有了這樣的優化,k也可以只用0,1來表示,1表示1號顏色,0表示非1號顏色。而m=2時就更簡單了,0,1就直接把顏色分開了。

初步分析下來,得到了乙個狀態數為o(n*k*2*2³),轉移為o(k*2*2³),總複雜度為o(n*k²*256)。由於n,k≤300,理論分析是會超時,但實際操作中可以不用迴圈到k,因為迴圈的上限可以設為min(k,子樹i的總節點數)。這樣的話,這個複雜度還是可以承受的。

本題還有優化嗎?答案是肯定的。

如果要優化狀態,前3維似乎是無法優化的,考慮第4維。之所以一開始要加入這一維,就是擔心會存在有一些顏色無法染上的問題,經過後來的分析,發現除了1號顏色會對答案有貢獻之外,其他顏色其實是可以被忽略的,因為我們可以保證它們不會對答案造成影響,那麼只要有足夠多的節點來染除1外的顏色,就可以確保每一種顏色都可以被染上,至於到底在**,其實並不重要。這樣想,就會發現其實第四維是完全多餘的,可以直接略去。

最終狀態:

f[i][j][k], 表示在以i為根的子樹中,有j個1號節點,根染k號顏色的狀態下最小的權值和。

注意:在具體轉移時,要先將原來的f[i]複製乙份,然後將f[i]清為無窮大,然後用備份的f[i]結合上述方程來計算f[i]的值。因為計算兒子沒計算完時的狀態是不能保留的,因為他們沒有考慮完所有的情況,嚴格來講,可以在上述方程中加上1維,表示計算到當前根的第幾個兒子,每一次都是有上一次的狀態和兒子的最終狀態合併。這樣就可以用滾動陣列或輔助陣列的方式來實現

設y是i的乙個兒子。

f[i][j][1]=min

f[i][j][0]=min

初始值,對於每乙個i,f[i][0][0]=f[i][1][1]=0.

答案為f[1][k][1]。

ac**:

#include#include

using

namespace

std;

#define n 305

struct

nodee[n

<<1

];int tot,head[n<<1

];int

n,m,k;

int sum[n],tmp[n][2],f[n][n][2

];inline

void min(int &x,int y,int

z)inline

void add(int x,int y,int

z)void dp(int x,int

from

),f[y][k][1]+pref[i][j-k][0]);

memcpy(tmp,f[x],sizeof

f[x]);

memset(f[x],

127/3,sizeof

f[x]);

for(j=sum[x];j+1;j--)}}

}int

main()

for(int i=1,x,y,z;i)

dp(1,0);

printf(

"%d\n

",f[1][k][1

]);

return0;

}

NOI2002 貪吃的九頭龍

description 傳說中的九頭龍是一種特別貪吃的動物。雖然名字叫 九頭龍 但這只是說它出生的時候有九個頭,而在成長的過程中,它有時會長出很多的新頭,頭的總數會遠大於九,當然也會有舊頭因衰老而自己脫落。有一天,有m個腦袋的九頭龍看到一棵長有n個果子的果樹,喜出望外,恨不得一口把它全部吃掉。可是必...

NOI 2002 貪吃的九頭龍

給出一棵 n 個節點的樹,邊有邊權,現要求你將這 n 個點劃分到 m 個集合,集合不許為空。另要求 1 號集合必須包含 1 號點,並且 1 號集合的大小必須正好為 k 如果一條邊連線的兩個點屬於同乙個集合,則這條邊的邊權將被計入總代價。問總代價最少為多少。分析題目性質。首先我們保證能劃分出 m 個集...

題解 NOI2002 貪吃的九頭龍

題目大意 有一棵樹,你需要將n個點染成m種顏色,且需滿足一下兩種條件 1.一號點必須是一號顏色,且一號顏色必須包含k個點 2.每種顏色必須包含至少乙個點 代價為若一條邊連線的顏色相同則得付出該邊的代價 求滿足以上兩種情況下的代價之和 首先,一眼看出是道樹dp題 然後日常套路,設f u j f u j...