HAOI2015 樹上染色(樹形dp)

2022-04-29 22:00:12 字數 1340 閱讀 3271

有一棵點數為 n 的樹,樹邊有邊權。給你乙個在 0~ n 之內的正整數 k ,你要在這棵樹中選擇 k個點,將其染成黑色,並將其他 的n-k個點染成白色 。 將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間的距離的和的受益。問受益最大值是多少。

輸入格式:

第一行包含兩個整數 n, k 。接下來 n-1 行每行三個正整數 fr, to, dis , 表示該樹中存在一條長度為 dis 的邊 (fr, to) 。輸入保證所有點之間是聯通的。

輸出格式:

輸出乙個正整數,表示收益的最大值。

輸入樣例#1:複製

3 11 2 1

1 3 2

輸出樣例#1:複製

對於 100% 的資料, 0<=k<=n <=2000

最開始我以為要處理出點與點之間的距離。

然後對於k的話實際上就是min(k,n-k)。

然後dp出最小價值的k個點對。

拿總路徑和減去最小dp值。

但是發現不好維護。

於是抄看了題解

對於乙個子樹內我要選取的黑點。

我們這一次dp的不僅是增加的黑點的價值,還要處理出減少的白點的價值。

也就是說每選乙個點,就要判斷這條路徑的貢獻變化了多少。

對於每條路徑的貢獻。

為當前子樹的黑節點×子樹外的黑節點×邊權+當前子樹的白節點×子樹外的白節點×邊權就可以了。

這樣就不用刻意去記錄點對了。

#include#include#include#include#include#define ll long long

using namespace std;

const int n=2001;

struct nodee[n<<2];

int n,k,num,head[n],size[n];

ll f[n][n];

ll read()

while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();

return x*w;

}void add(int from,int to,int v)

void dfs1(int x,int fa)

}void dfs2(int x,int fa)}}

}}int main()

memset(f,-1,sizeof(f));

dfs1(1,1);dfs2(1,1);

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

return 0;

}

HAOI2015 樹上染色

有一棵點數為 n 的樹,樹邊有邊權。給你乙個在 0 n 之內的正整數k,你要在這棵樹中選擇 k 個點,將其染成黑色,並將其他的 n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。輸入第一行兩個整數 n,k。接下來 n 1 行每行三個正整...

HAOI2015 樹上染色

考慮子樹當中所有邊的貢獻即可。然後就能簡單做樹上揹包了。但是要注意列舉的順序,應該從大到小更新,否則某個狀態會多次被加。如果不想考慮列舉順序,那麼直接dp的時候用乙個臨時陣列記錄。ac pragma gcc optimize ofast funroll all loops include defin...

HAOI2015 樹上染色

嘟嘟嘟 首先這一眼看出來,要樹形dp。然後發現狀態不好設,剛開始我想的是dp i j 表示以 i 為根的子樹,選了 j 個黑點的最大價值。結果就不會轉移了。轉移的時候想考慮 這一條邊的貢獻,但是發現這個狀態的轉移所涉及的不只是這一條邊,還有子樹中的邊,於是就徹底gg了。還是看了題解。題解也是考慮貢獻...