題目
一道非常好的樹形dp。
狀態:\(dp[u][n]\)為u的子樹選n個黑點所能得到的收益最大值。
則最終的結果就是\(dp[root][k],\)
\(root\)可以為任何值,為了方便,使\(root=1\)
然後考慮怎麼狀態轉移,狀態轉移一般要從方程和邊界入手,考慮用揹包的思想,得到方程:
\[dp[now][j]=max(dp[now][j], dp[now][j-l]+dp[to][l]+子樹選l個黑點的貢獻)
\]\((0<=j<=min(k, size[now]), 0<=l<=min(j,size[to]))\)
接下來問題轉化為如何求他們的貢獻
根據題意,貢獻就是(黑點的距離和+白點的距離和)=(黑節點數\(*\)另一端黑節點邊權+白節點數\(*\)另一端白節點邊權)\(*\)e[i].len.
\(e[i].len * ( (k - l) * l + (siz[to] - l) * (n - k - siz[to] + l) )\)
且這只能由\(dp[now][j-l]\)已被更新的情況下才可以更新。
#include #define int long long
using namespace std;
int n, k, cnt, root, lin[3010], vis[3010], siz[3010], dp[3010][3010];//每個點的最短路
struct edg e[4001011];
inline void add(int f, int t, int l)
void init(int now, int fa, int de)
return;
} void dfs(int now, int fa)
//此時他的子樹都已經搜尋完了。
for (int i = lin[now]; i; i = e[i].nex)
}}signed main()
洛谷P3177 樹上染色
題意 給n,k,n個點的樹,k個點是黑色的,n k點是白色的 給n 1條u,v,w,收益值是黑點兩兩距離之和,和白點兩兩距離之和的總值 求最大的收益值 思路 因為是樹形的,所以想到了求dp,dp u i 求u為根的選有多少i個黑點的收益值,然後卡殼 翻了題解,發現dp u i 求得是以u為根的 i ...
洛谷 P3177 HAOI2015 樹上染色
懶得複製題面了直接傳送門吧 直接求點與點之間的距離感覺不是很好求,所以我們考慮換乙個求法。瞄了一眼題解 距離跟路徑上邊的長度有關,所以我們直接來看每一條邊的貢獻吧 這誰想得到啊 對於每一條邊,它的貢獻等於 一邊的白點數 另一邊的白點數 一邊的黑點數 另一邊的黑點數 邊權 然後。我又卡住了。再次瞄題解...
洛谷 P3177 HAOI2015 樹上染色
有一棵點數為 n 的樹,樹邊有邊權。給你乙個在 0 n 之內的正整數 k 你要在這棵樹中選擇 k 個點,將其染成黑色,並將其他 的 n k 個點染成白色 將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間的距離的和的受益。問受益最大值是多少。有點難想的dp 我果然太菜了 stdcall f ...