树形DP

1.hdoj 1520 Anniversary party

在父亲与儿子之间状态转移

#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;
}


.

posted on 2011-03-06 22:10  CrazyAC  阅读(973)  评论(0编辑  收藏  举报