http://poj.org/problem?id=2342 题意:要聚会了,有n个员工,n-1个上下属关系连成一棵树,每个员工有一个快乐值,可以为负,如果某个员工参加聚会,则他的直接上司不能去参加聚会,求最
http://poj.org/problem?id=2342
题意:要聚会了,有n个员工,n-1个上下属关系连成一棵树,每个员工有一个快乐值,可以为负,如果某个员工参加聚会,则他的直接上司不能去参加聚会,求最终聚会的人总的快乐值最大多少。
题解:找到树的根节点进行dfs,dp[x][1]表示以x去参加聚会,值为根节点的子树的最大值,也就是把所有儿子y的dp[y][0]加起来,x参加则他的直接下属不能参加;dp[x][0]表示x不去参加聚会,则他的直接下属可去可不去,累加儿子状态的最大值,即max(dp[y][0],dp[y][1]);不用考虑儿子参加的快乐值是否大于0,如果小于0则会在max中会取dp[y][0]使得dp[x][0]不会小于0。
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> #include<string> #include<map> #include<queue> #include<stack> #include<set> #define ll long long #define inf 0x3f3f3f3f using namespace std; int n; vector<int>son[6005]; int dp[6005][2]; bool vis[6005]; void dfs(int x) { for(int i=0;i<son[x].size();i++) { int y=son[x][i]; dfs(y); dp[x][0]+=max(dp[y][1],dp[y][0]); dp[x][1]+=dp[y][0]; } } int main() { while(scanf("%d",&n)!=EOF) { memset(dp,0,sizeof(dp)); memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++) scanf("%d",&dp[i][1]);///初始化dp[i][1]表示i参加聚会的快乐值 int k,l; for(int i=1;i<n;i++) { scanf("%d%d",&l,&k); son[k].push_back(l); vis[l]=true;///u有上司 } scanf("%d%d",&l,&k); for(int i=1;i<=n;i++) { if(!vis[i])//找到根节点 { dfs(i); printf("%d\n",max(dp[i][0],dp[i][1])); break; } } } return 0; }