树形DP
在父亲与儿子之间状态转移
#include <iostream> #include <vector> using namespace std; struct Node { int choose, unchoose; int max() { return choose > unchoose ? choose : unchoose; } }ns[6005]; vector<int> vec[6005]; int n; void treeDP( int father ) { int i, sz, son; sz = vec[father].size(); for( i=0; i<sz; ++i ) { son = vec[father][i]; treeDP( son ); ns[father].choose += ns[son].unchoose; ns[father].unchoose += ns[son].max(); } } int main() { // freopen( "c:/aaa.txt", "r", stdin ); int i, a, b, in[6005]; while( scanf( "%d", &n ) != EOF ) { for( i=1; i<=n; ++i ) { scanf( "%d", &ns[i].choose ); ns[i].unchoose = 0; in[i] = 0; vec[i].clear(); } while( scanf("%d %d", &a, &b ) == 2 && a + b ) { in[a] ++; vec[b].push_back( a ); } for( i=1; i<=n; ++i ) if( in[i] == 0 ) break; treeDP( i ); printf( "%d\n", ns[i].max() ); } return 0; }
2.hdoj 1561 The more, The Better
树形dp + 01背包
网上看到的解释:状态 dp[i][j] 为以 i 为根节点,选出 j 个节点的最大价值(包括 i 这个节点)则转移方程:dp[i][j]=max(dp[i1][j1]+dp[i2][j2]+....+dp[ik][jk])+a[i] j1+j2+...+jk=j-1
记 dp0[i][j] 为以 i 为根节点,它的分支中取出 j 个节点的最大价值,那么转移方程就是经典的背包 dp0[i][j+k]=max{dp0[i][j+k],dp0[i][j]+dp[son[i]][k]}
不过我觉得dp0[i][j]表示从i的分支中选j个点,所以这j个点可能包含son[i]这个点,然后又加上dp[son[i]][k],这样son[i]岂不是重复计算了?。。。
#include <iostream> #include <vector> using namespace std; int num[205], dp[205][205], dp0[205][205]; vector<int> vec[205]; bool mark[205]; int n, m; void init() { int i; for( i=0; i<=n; ++i ) { vec[i].clear(); mark[i] = 0; } memset( dp, -1, sizeof(dp) ); memset( dp0, -1, sizeof(dp0) ); } //int max( int a, int b ) { return a > b ? a : b; } void dfs( int father ) { int son, i, j, k, sz; if( mark[father] ) return; mark[father] = 1; dp0[father][0] = 0; sz = vec[father].size(); for( i=0; i<sz; ++i ) { son = vec[father][i]; if( !mark[son] ) dfs( son ); for( j=m; j>=0; --j ) { for(k=1; k+j<=m; ++k ) { if( dp0[father][j] != -1 ) dp0[father][k+j] = max( dp0[father][k+j], dp0[father][j] + dp[son][k] ); } } } for( i=0; i<=m; ++i ) { if( dp0[father][i] != -1 ) dp[father][i+1] = dp0[father][i] + num[father]; } } int main() { // freopen( "c:/aaa.txt", "r", stdin ); int i, a, b; while( scanf( "%d %d", &n, &m ) == 2 && n+m) { init(); for( i=1; i<=n; ++i ) { scanf( "%d %d", &a, &b ); vec[a].push_back( i ); num[i] = b; } dfs( 0 ); printf( "%d\n", dp[0][m+1] ); } return 0; }
.