藍橋杯 演算法訓練-結點選擇
阿新 • • 發佈:2019-01-08
問題描述
有一棵 n 個節點的樹,樹上每個節點都有一個正整數權值。如果一個點被選擇了,那麼在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?
解題思路
很簡單的一道入門樹狀dp,把求最終解分成兩種情況
- 根結點被選中,則所有的子節點一定不能被選中
- 根節點沒被選中,則子節點可被選中,注意是可以被選中,有的最優解中很可能不選擇某一個子節點而選擇子節點的子節點。
設
d(r,1)=v(r)+∑d(ci,0)
d(r,0)=∑max{d(ci,1),d(ci,0)}
則最終的結果就是選根節點兩種情況中最大的一個
#include <iostream>
#include <cstring>
#define N 100000
#define MAX(x, y) ((x)>(y)?(x):(y))
struct edge
{
int to;
int next;
};
int tree[N];
int weight[N];
edge edges[2*N];
int d[N][2];
int len = 0;
void add(int x, int y)
{
edges[len].to = y;
edges[len].next = tree[x];
tree[x] = len++;
}
void dp(int root, int p)
{
if(tree[root] == -1)
{
d[root][0] = 0;
d[root][1] = weight[root];
return;
}
for(int i = tree[root]; i != -1; i = edges[i].next)
{
int child = edges[i].to;
if(child == p)
continue;
if(!d[child][1])
dp(child, root);
d[root][0 ] += MAX(d[child][1], d[child][0]);
d[root][1] += d[child][0];
}
d[root][1] += weight[root];
}
int main()
{
memset(tree, -1, sizeof(tree));
int n;
std::cin >> n;
for(int i = 1; i <= n; i++)
std::cin >> weight[i];
int x, y;
for(int i = 0; i < n-1; i++)
{
std::cin >> x >> y;
add(x, y);
add(y, x);
}
dp(1, -1);
int max = MAX(d[1][0], d[1][1]);
std::cout << max << std::endl;
}