CF1249F Maximum Weight Subset
題意
給出一個樹,每個點有權值
求最大權值子集,且子集任意一對點的距離大於
思路
-
明顯的樹上
-
令 表示以 爲根的子樹,最小深度爲 的最大符合條件的子集
-
對於一個點,以 爲根,以 爲子樹爲根,顯然有兩種情況
-
子集包含 那麼只需要加上 的每個子樹深度爲 的最大子集即可
-
for (auto it : E[now]) { if (it == fa) continue; dp[now][0] += dp[it][k]; //與it距離爲k,與now距離k+1 }
-
若不取 則需要枚舉深度爲 的點所在的子樹,其他子樹上的子集與該點距離應大於
-
for (int i = 1; i < n; i++) { for (auto it : E[now]) {//枚舉距離爲j的點 if (it == fa) continue; int cnt = dp[it][i - 1]; for (auto other : E[now]) { if (other == it || other == fa) continue; cnt += dp[other][max(i - 1, k - i)];//至少距離爲i-1 } dp[now][i] = max(dp[now][i], cnt); } }
-
-
複雜度
-
這個算法很容易估算爲 ,但其實是
-
因爲在算複雜度時,大家往往會忽略 在枚舉子樹的過程是 的,因爲一棵樹是隻有條邊
代碼
#include <bits\stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 205;
int a[maxn];
vector<int> E[maxn];
int n, k;
int dp[maxn][maxn];
void dfs(int now, int fa)
{
dp[now][0] = a[now];
for (auto it : E[now]) {
if (it == fa)
continue;
dfs(it, now);
}
for (auto it : E[now]) {
if (it == fa)
continue;
dp[now][0] += dp[it][k];
}
for (int i = 1; i < n; i++) {
for (auto it : E[now]) {
if (it == fa)
continue;
int cnt = dp[it][i - 1];
for (auto other : E[now]) {
if (other == it || other == fa)
continue;
cnt += dp[other][max(i - 1, k - i)];
}
dp[now][i] = max(dp[now][i], cnt);
}
}
for (int i = n - 1; i >= 0; i--)
dp[now][i - 1] = max(dp[now][i - 1], dp[now][i]);
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
int u, v;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
E[u].push_back(v);
E[v].push_back(u);
}
dfs(1, 0);
printf("%d\n", dp[1][0]);
return 0;
}
back(v);
E[v].push_back(u);
}
dfs(1, 0);
printf("%d\n", dp[1][0]);
return 0;
}