題幹:
有一棵點數為 n 的樹,樹邊有邊權。給你乙個在 0∼n 之內的正整數 k,你要在這棵樹中選擇 k 個點,將其染成黑色,並將其他的 n−k 個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。
題解:
首先,看到黑點到黑點、白點與白點,其實這就告訴我們黑點與白點是可以整體互換的(可以由黑點染成白色變為白點染成黑色),這就代表我們的 k 一定 <=(n/2)。
然後看到本題在樹上進行操作,那麼就應該是樹上dp(合理分析。。。)
相應地,我們先 dfs 出所有子樹的大小,然後想一下 dp 狀態轉移方程。
第一維不出意外應是以 i 為根節點的樹(然後怎麼怎麼樣~~~)。
第二維呢?我們好像只能是定義為以 i 為根節點的樹,這個樹中有 j 個節點被染色的情況。
我們每染兩個點,就會對全域性都造成影響,所以 dp 的結果值應定義為對全域性的貢獻,而不是以這個節點為根節點的子樹的貢獻。
再看一下這兩個相同顏色的點是如何作出貢獻的。我們可以發現,我們要輸出的結果就是所有邊權乘上各自被經過的次數。
這每乙個邊各自被經過的次數怎麼算呢?—— 我們可以看一下每乙個邊兩旁的節點,發現兩旁每有一對相同顏色的節點,它就會被經過一次。
最後用乘法分配律可得:針對每一條邊,它被經過的次數就是:
左邊白點個數×右邊白點個數+左邊黑點個數×右邊黑點個數
最後利用樹上揹包來解決(體積為染色點的個數,價值就為對全域性的貢獻)。
(注意本題的揹包與以往經典例題的方法不太一樣,它有一定後效性,
只可以在更新部分最優的同時,進行現在貢獻的統計;而不是先找出子節點的最優,再找出現在的最優進行相加)
我們再回過頭來看一下我們的演算法,好像是 o(n3) 的!!!(列舉一遍節點 × 大小為n的子樹體積 × 大小為n的其餘樹體積)。。。但仔細分析一下其實是 o(n2) 的:
1、在實現過程中,其實我們在更新答案時是列舉了整個數的乙個子樹(設大小為 x)與其餘部分(設大小為 y ),那麼每乙個小子樹的複雜度為 o(x*y)
(為什麼是 o(x*y) 呢?本題的核心在於將染色的節點數作為揹包,那麼每一棵子樹的大小就是揹包的最大體積,即在列舉時我們在 0~x 中又列舉了 0~y):
σsiz
j=0 σsiz2
m=0val=w*( m*(k-m) + (siz[son]-m)*(n-k-(siz[son]-m)) );
dp[x][m+j]=max(dp[x][m+j],dp[x][j]+dp[son][m]+val);
2、相應的大子樹同理,那麼我們用乘法結合律可得:我們相當於將每乙個結點都乘過了除它以外的所有節點——n個節點×n個節點——o(n2)。
o(n2) 中注意要枚舉子樹的大小,而不是全掃一邊,否則就一定會退化為o(n3) 。
code:
1 #include2 #include3view code#define $ 2102
4#define ll long long
5using
namespace
std;
6int
n,first[$],tot,m,siz[$];
7 ll dp[$][$/2];8
struct treea[$*2
];9 inline int min(int x,int y)
10 inline ll max(ll x,ll y)
11 inline void add(int x,int y,int
w);13 first[x]=tot;
14 a[++tot]=(tree);
15 first[y]=tot;16}
17 inline void dfs(int x,int fa,int sum=1)25
for(register int i=first[x];i;i=a[i].next)35}
36 sum=min(m,sum+siz[to]);37}
38}39signed main()
HAOI2015 樹上染色(樹形dp,樹形揹包)
題目描述 有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並將其他的n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。輸入描述 第一行兩個整數n,k。接下來n 1行每行三個正整數f...
子樹合併揹包型別的dp的複雜度證明
狀態形如f x j f x j 表示x x 子樹內選了 j role presentation style position relative j j個,轉移形如f x j k f x j f y k f x j k f x j f y k 假設樹上有n個點,第二維限制為k 最多選k個 我們熟知,這...
01揹包問題 空間複雜度o V
題目 有n件物品和乙個容量為v的揹包。第i件物品的所需容量是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。f i v 表示前i件物品恰放入乙個容量為v的揹包可以獲得的最大價值。現在我們來看第 件物品 如果選擇將第 件物品放入,那麼在放置前 件物品的時候應該空出 i 的容量,此時方程為...