树形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;
}
.
浙公网安备 33010602011771号