樹DP
經典問題,公司聚會,下屬和直屬上司不能共存,給出每個人的快樂值,再給出每個人的編號和他的上司,選出一些人蔘加聚會使快樂值最大
/*從葉子開始選擇,每個節點只有選不和不選兩種可能,dp[rt][0],dp[rt][1]分別表示選和不選該節點dp[rt][1]=sum{ dp[son][0] }+val[rt] , 因為跟選了它的兒子就全部不能選dp[rt][0]=sum{ max{dp[son][0] , dp[son][1]} }如果根不選,那麼兒子的選擇就多樣化了,每個兒子又是互不干擾的所以令每個兒子最優,加起來根就是最優的,而每個孩子無非還是選和不選,一比較就能得到每個兒子的最優方案而對於葉子,dp[rt][0]=0;dp[rt][1]=val[rt];*/#include <cstdio>#include <cstring>#include <vector>using namespace std;#define N 6010vector<int>a[N];int dp[N][2];int val[N];int n,root;bool mark[N],vis[N];int max(int p ,int q){ return p>q?p:q;}void dfs(int rt){ vis[rt]=true; int size=a[rt].size(); dp[rt][0]=0; dp[rt][1]=val[rt]; for(int i=0; i<size; i++) { int son=a[rt][i]; if(!vis[son]) { dfs(son); dp[rt][1] += dp[son][0]; dp[rt][0] += max(dp[son][0] , dp[son][1]); } }}void solve(){ for(int i=1; i<=n; i++) if(!mark[i]) { root=i; break; } a[0].push_back(root); a[root].push_back(0); root=0; val[root]=0; memset(vis,false,sizeof(vis)); dfs(root); printf("%d\n",max(dp[root][0] , dp[root][1]));}int main(){ while(scanf("%d",&n)!=EOF) { memset(mark,false,sizeof(mark)); for(int i=1; i<=n; i++) a[i].clear(); for(int i=1; i<=n; i++) scanf("%d",&val[i]); while(1) { int u,v; scanf("%d%d",&u,&v); if(!u && !v) break; mark[u]=true; a[u].push_back(v); a[v].push_back(u); } solve(); } return 0;}