节点选择(树形dp)
#include <bits/stdc++.h> using namespace std; int tree[100001],dp[100001],p[100001],n,x,y,mask[100001]={0},sons[100001]={0}; int rdp1[100001],rdp2[100001]={0},vis[100001]={0}; //树形dp,从下往上更新,具体见算法入门经典 //节点选择除了自上而下和枚举子子的另一种解法: //用F[i]表示i这条根要,G[i]表示不要(也可以用f[i][1,0]来表示 // f[root]+=g[ee[i].y]; //g[root]+=max(f[ee[i].y],g[ee[i].y]); //要了就子不能要,没要,要不要都行 vector<int> points[100001]; queue<int> q; void build(){ queue<int> qq; qq.push(1); vis[1]=1; while(!qq.empty()){ int pp=qq.front(); qq.pop(); for(vector<int>::iterator i=points[pp].begin();i!=points[pp].end();i++){ if(vis[*i]==0){ vis[*i]=1; qq.push(*i); p[*i]=pp; sons[pp]++; } } } } int main() { cin>>n; for(int i=1;i<=n;i++){ cin>>tree[i]; rdp1[i]=tree[i]; p[i]=-1; } for(int i=1;i<n;i++){ cin>>x>>y; points[x].push_back(y); points[y].push_back(x); mask[x]++; mask[y]++; } build(); for(int i=1;i<=n;i++) if(mask[i]==1) q.push(i); while(!q.empty()){ int point=q.front(); q.pop(); dp[point]=max(rdp1[point],rdp2[point]); if(p[point]!=-1){ rdp2[p[point]]+=dp[point]; if(p[p[point]]!=-1) rdp1[p[p[point]]]+=dp[point]; sons[p[point]]--; if(sons[p[point]]==0) q.push(p[point]); } } cout<<dp[1]<<endl; return 0; }