[bzoj4033][haoi2015]樹上染色
試題描述
有一棵點數為n的樹,樹邊有邊權。給你乙個在0~n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並
將其他的n-k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。
問收益最大值是多少。
輸入
第一行兩個整數n,k。
接下來n-1行每行三個正整數fr,to,dis,表示該樹中存在一條長度為dis的邊(fr,to)。
輸入保證所有點之間是聯通的。
n<=2000,0<=k<=n
輸出
輸出乙個正整數,表示收益的最大值。
輸入示例
5212315
1231
242
輸出示例
17
資料規模及約定
見「輸入」
題解
樹形 dp,設 f(i, j) 表示對於子樹 i,選 j 個黑點所能得到的邊的最大貢獻,注意這裡邊的貢獻是全域性的,不是只考慮子樹內部的,這樣做比較方便轉移。
那麼在轉移的時候,對於節點 u,我們在樹上做揹包,就是列舉每個兒子分別選幾個黑點然後合併。這樣看上去很暴力,但是我們可以證明總轉移複雜度不超過 o(n2)。其實就是要證明 o(∑u=1..n∑v,w是u的兒子siz[v]·siz[w]) = o(n2)。我們不妨把「∑v,w是u的兒子siz[v]·siz[w]」這一部分看做每次從 u 的每個子樹中任選兩個點 (a, b) 使得 a 和 b 的最近公公祖先恰好為 u 的方案數,那麼每個節點只可能一次成為最近公公祖先,那麼整個「∑u=1..n∑v,w是u的兒子siz[v]·siz[w]」其實就是樹中點對個數,所以是 n2 的。
#include #include #include #include #include #include using namespace std;#define ll long long
ll read()
while(isdigit(c))
return x * f;
}#define maxn 2010
#define maxm 4010
int n, k, m, head[maxn], nxt[maxm], to[maxm];
ll dist[maxm];
void addedge(int a, int b, ll c)
ll f[maxn][maxn];
int siz[maxn];
void build(int u, int fa)
if(siz[u] == 1)
int sum = 1;
f[u][0] = f[u][1] = 0;
for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa)
return ;
}int main()
memset(f, -1, sizeof(f));
build(1, 0);
printf("%lld\n", f[1][k]);
return 0;
}
bzoj4033 HAOI2015 樹上染色
題目鏈結 有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並 將其他的n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。第一行兩個整數n,k。接下來n 1行每行三個正整數fr,to...
bzoj4033 HAOI2015 樹上染色
有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並 將其他的n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。輸入保證所有點之間是聯通的。n 2000,0 k n 來自 臥槽原來我...
BZOJ 4033 HAOI2015 樹上染色
time limit 10 sec memory limit 256 mb submit 2569 solved 1088 submit status discuss description 有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並 ...