链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520
题意:给你一 棵关系树,让你从中选择若干个人,这些人之间不能有直接的上下级关系,要求最后的到的权值最大
树形dp在设状态转移方程时都可以用f[i][]表示i这颗子树怎么怎么样的最优解,实现时一般都是用子树更新父亲(即从下向上更新),那么首先应该考虑的是一个一个子树的更新父亲还是把所有子树都算完了在更新父亲?这就要因题而异了,一般来说有两种情况:1.需要把所有子树的信息都掌握之后再更新子树的就需要把所有子树都算完了在更新父亲。2.而像树上背包这样的问题就需要一个一个的更新,每次都用一个子树更新已经更新完的子树+父亲,最后就可以将这一部分的子树更新完了,再继续往上更新,最后根节点就是答案。
思路:树形dp,比较好理解
代码:
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=6006;
queue<int>q;
vector<int>v[maxn];
int val[maxn];
int dp[maxn][2];
int fa[maxn];void dfs(int rt){for(int i=0;i<v[rt].size ();i++){int temp=v[rt][i];dfs(temp);dp[rt][0]+=max(dp[temp][0],dp[temp][1]);dp[rt][1]+=dp[temp][0];}
}int main(){int n;while(~scanf("%d",&n)){for(int i=1;i<=n;i++){v[i].clear ();scanf("%d",&val[i]);fa[i]=-1;dp[i][1]=val[i];dp[i][0]=0;}int a,b;while(~scanf("%d%d",&a,&b),(a+b)){fa[a]=b;v[b].push_back (a);}for(int i=1;i<=n;i++){if(fa[i]==-1){dfs(i);printf("%d\n",max(dp[i][0],dp[i][1]));break;}}}
}