題解 NOI2002 貪吃的九頭龍

2021-08-19 20:46:35 字數 1801 閱讀 5044

題目大意

有一棵樹,你需要將n個點染成m種顏色,且需滿足一下兩種條件

1.一號點必須是一號顏色,且一號顏色必須包含k個點

2.每種顏色必須包含至少乙個點

代價為若一條邊連線的顏色相同則得付出該邊的代價

求滿足以上兩種情況下的代價之和

首先,一眼看出是道樹dp題

然後日常套路,設f[

u][j

] f[u

][j]

表示以u u

為子樹包含

j' role="presentation">j

j種一號顏色下的最小代價,然後發現無法判斷兩個點之間是否顏色相同,於是再加一維f[

u][j

][0/

1]f [u

][j]

[0/1

]表示在

u u

號點上是否染為一號顏色

然後開始最重要的yy

如果m==2的話,一條邊連線的兩個點只有乙個為1乙個不為1的情況下才不會付出代價

如果m>2的話,一條邊連線的兩個點只要不是都為1就不會付出代價

為什麼呢?

顯然可以通過奇偶性來強制兩個點顏色不同,且滿足條件

然後dp方程就是

f[u][j][0]=min(f[u][j][0],min(f[v][t][0]+f[u][j-t][0]+(m==2)*e[i].w,f[v][t][1]+f[u][j-t][0]));

f[u][j][1]=min(f[u][j][1],min(f[v][t][1]+f[u][j-t][1]+e[i].w,f[v][t][0]+f[u][j-t][1]));

然後驚奇的發現其實我們連樣例都過不了(尷尬)

於是重新審視dp方程

我們需要每次dp前將之前的f陣列備份下來,不然的話f值在dp中會越來越小,當然如果n也很小的話其實也沒什麼影響

所以我們用tmp[j][0/1]來存f[u]陣列的值

f[u][j][0]=min(f[u][j][0],min(f[v][t][0]+tmp[j-t][0]+(m==2)*e[i].w,f[v][t][1]+tmp[j-t][0]));

f[u][j][1]=min(f[u][j][1],min(f[v][t][1]+tmp[j-t][1]+e[i].w,f[v][t][0]+tmp[j-t][1]));

然後就能愉快的ac了

好了,上**

#include

#include

#include

using

namespace

std;

const

int _=305;

inline

int read()

int n,m,k,f[_][_][2],tmp[_][2];

struct hande[_<<1];

int cnt,head[_];

void link(int u,int v,int w)

; head[u]=cnt;

}void dfs(int u,int fa)}}

}int main()

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

link(x,y,z);link(y,x,z);

}memset(f,63,sizeof(f));

dfs(1,1);

printf("%d\n",f[1][k][1]);

return

0;}

NOI2002 貪吃的九頭龍

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

NOI 2002 貪吃的九頭龍

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

NOI2002 貪吃的九頭龍

p2940貪吃的九頭龍 貪吃的九頭龍 dragon.pas c cpp 問題描述 傳說中的九頭龍是一種特別貪吃的動物。雖然名字叫 九頭龍 但這只是說它出生的時候有九個頭,而在成長的過程中,它有時會長出很多的新頭,頭的總數會遠大於九,當然也會有舊頭因衰老而自己脫落。有一天,有m個腦袋的九頭龍看到一棵長...