/* http://acm.hdu.edu.cn/showproblem.php?pid=1520 Anniversary party 比较典型的树形dp,好题目!!! 给一棵树,要求取某一个节点(每一个点有权值)时不能取对应的父节点和子节点,问满足条件的方案权值最大为多少。 定义状态dp[i][0]表示不取i节点时的最大权值,dp[i][1]表示取i节点时的最大权值。 所以 dp[father][0] = max(dp[father][0] + dp[child][1] , dp[father][0] + dp[child][0]) dp[father][1] = dp[father][1] + dp[child][0] ; 在题目中,我们设一个0节点作为整个“森林”(因为不确定是不是树)的root节点; 我们只需要将结果递推到dp[0][0]即可。 题目中对数据的输入没有描述清楚,其实有多组测试数据,两组之间有0 0隔开,最后还有一个0结束,否则将无限TLE */ #pragma comment(linker, "/stack:64000000") #define _CRT_SECURE_NO_DEPRECATE #include <queue> #include <cmath> #include <cstdio> #include <string> #include <cstring> #include <iostream> using namespace std; #define CLR(c,v) memset(c,v,sizeof(c)) template <typename _T> _T Max(_T a , _T b){ return (a>b)?(a):(b); } template <typename _T> _T Max(_T a , _T b, _T c){ return (a>Max(b,c))?(a):(Max(b,c)); } template <typename _T> _T Min(_T a , _T b){ return (a<b)?(a):(b); } template <typename _T> _T Min(_T a , _T b, _T c){ return (a<Min(b,c))?(a):(Min(b,c)); } const int inf = -(1<<30); const int INF = (1<<30); const double eps = 1e-8; const int M = 6e4 +10; vector <int > p[M]; int f[M]; int dp[M][2]; void dfs(int cur){ int size = p[cur].size(); for(int i = 0 ; i < size ; i++){ int child = p[cur][i]; dfs(child); int father = cur; dp[father][0] += Max(dp[child][0],dp[child][1]); dp[father][1] += dp[child][0]; } } int main(){ //freopen("in.txt","r",stdin); int n,v; while(cin >> n && n!=0){ CLR(f,0); CLR(dp,0); p[0].clear(); for (int i = 1; i <= n ; i++){ scanf("%d" , &v); f[i] = i; dp[i][1] = v; if(!p[i].empty())p[i].clear(); } for (int a,b ,i=1; scanf("%d%d",&a,&b) && a!=0&&b!=0 ; i++){ p[b].push_back(a); f[a] = b; } for (int i = 1 ; i <= n ; i++){ // 把森林或树的root加入0节点下 if(f[i] == i) p[0].push_back(i); } dfs(0); cout << dp[0][0] << endl; } return 0; }