HAOI2015 樹上染色

2022-05-09 11:03:09 字數 1478 閱讀 5173

嘟嘟嘟

首先這一眼看出來,要樹形dp。

然後發現狀態不好設,剛開始我想的是dp[i][j]表示以\(i\)為根的子樹,選了\(j\)個黑點的最大價值。結果就不會轉移了。

轉移的時候想考慮\(\)這一條邊的貢獻,但是發現這個狀態的轉移所涉及的不只是這一條邊,還有子樹中的邊,於是就徹底gg了。

還是看了題解。

題解也是考慮貢獻,而且也是考慮每一條邊,但最大的區別是,我們列舉邊,然後考慮邊兩側的點對答案的貢獻。

令dp[i][j]表示以\(i\)為根的子樹,選了\(j\)個黑點,已經列舉到第\(x\)條邊時,當前答案的最大值。

因為dfs的時候就相當於列舉邊了,所以這一維自然省去。

於是對於黑點,有\(j * (k - j) * w(u, v)\)的貢獻,

對於白點,有\((k - j) * (n - size[v] - (k - j)) * w(u, v)\)的貢獻。

最後記得要初始化dp陣列為-inf,因為有些狀態不合法。

#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define enter puts("")

#define space putchar(' ')

#define mem(a, x) memset(a, x, sizeof(a))

#define in inline

typedef long long ll;

typedef double db;

const int inf = 0x3f3f3f3f;

const db eps = 1e-8;

const int maxn = 2e3 + 5;

inline ll read()

while(isdigit(ch))

if(last == '-') ans = -ans;

return ans;

}inline void write(ll x)

int n, k;

struct edge

e[maxn << 1];

int head[maxn], ecnt = -1;

in void addedge(int x, int y, ll w)

; head[x] = ecnt;

}int siz[maxn];

ll dp[maxn][maxn];

in void dfs(int now, int _f)

}int main()

for(int i = 1; i <= n; ++i) fill(dp[i] + 1, dp[i] + k + 1, inf);

//帶勁的操作

dfs(1, 0);

write(dp[1][k]), enter;

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 樹上染色

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