題目大意
有一棵樹,你需要將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個腦袋的九頭龍看到一棵長...