补之前的比赛,发现一个板子题,当时却没做出来,现在去复习了一下当时的知识,树形dp
板子题: 没有上司的舞会
上面这个是老板子题了,但是每次重做都会让我回忆起来相关的知识
树形 dp 的核心就是
摘选自:【树形DP】树形DP入门详解+例题剖析_繁凡さん的博客-CSDN博客_树形dp
思路分析:
上司去与不去是两种情况,我们只需要把两种情况都分析出来,当然先去想的肯定是暴力,但是这题的数据范围是6e3所以我们暴力肯定是要超时的,但是思路有了,接下来就是优化了,因为分为两种情况,所以就分为 f[x][0],f[x][1] ,分别代表第 x 的人去与不去与他的上司 y 的关系则是
f[x][0]+=max(f[y][0],f[y][1]);
f[x][1]+=f[y][0];
递推公式有了,接下来就是代码了
#include<bits/stdc++.h>
using namespace std;
const int N = 6e4+7;
int n,m,root;
int f[N][2]={0};//去或者不去
int happy[N]={0};// happy
int head[N],ver[N], nex[N] ,tot;
bool vis[N];
void IOS(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
void add(int x,int y){
ver[tot]=y;
nex[tot]=head[x];
head[x]=tot++;
}
void dfs(int x,int fa){
f[x][0]=0;
f[x][1]=happy[x];
for(int i=head[x];~i;i=nex[i]){
int y=ver[i];
if(y==fa)continue;
dfs(y,x);
f[x][0]+=max(f[y][0],f[y][1]);
f[x][1]+=f[y][0];
}
}
int main(){
IOS();
memset(head,-1,sizeof(head));
cin>>n;
for(int i=1;i<=n;i++)cin>>happy[i];
for(int i=1;i<=n-1;i++){
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
vis[x]=1;
}
for(int i=1;i<=n;i++){
if(vis[i]==0){
root=i;//找根
break;
}
}
dfs(root,0);
cout<<max(f[root][0],f[root][1])<<endl;
return 0;
}