树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 6010 vector<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; }