[LuoguP1352][FJSC]没有上司的舞会

[LuoguP1352][FJSC]没有上司的舞会(Link

现在你有一棵树,每一个点有一个点权(R[i]),如果选择了(i)点,那么(i)子树上的所有的点都不能选,现在要求选择若干个点,使得点权和最大。

(Dp[i][1])为选择(i)点的(i)子树的最大点权和,(Dp[i][0])为不选择(i)点的(i)子树的最大点权和,那么我们知道初始化为

(Dp[i][0] = sum max(Dp[Son][1], Dp[Son][0]))

(Dp[i][1] = sum Dp[Son][0])

因为如果选了(i)点,那么下面的所有的点都不能选了,但是如果没选(i),那么下面的点选不选都行。由于(i)点是由其子节点转化而来的,所以考虑从入度为零的点开始边深搜边(Dp)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
const int MAXN = 100010 ;
const int MAXM = 100010 ;
int N, H[MAXN], Tot, R[MAXN], Dp[MAXN][2], Ind[MAXN], Root ;
struct Node {
	int F, T, Next ;
}E[MAXN << 1] ;

inline void Add(int F, int T) {
	E[++ Tot].F = F, E[Tot].T = T ;
	E[Tot].Next = H[F], H[F] = Tot ;
}

inline int Read() {
	int X = 0, F = 1 ; char ch = getchar() ;
	while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
	while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
	return X * F ;
}

inline void Dfs(int Now) {
	Dp[Now][0] = 0 ; Dp[Now][1] = R[Now] ;
	for (int i = H[Now] ; i ; i = E[i].Next) {
		Dfs(E[i].T) ;
		Dp[Now][0] += max(Dp[E[i].T][0], Dp[E[i].T][1]) ;
		Dp[Now][1] += Dp[E[i].T][0] ;
	}
}

int main() {
	N = Read() ; 
	for (int i = 1 ; i <= N ; i ++) R[i] = Read() ;
	for (int j = 1 ; j <= N ; j ++) {
		int X = Read(), Y = Read() ; 
		if (j == N) break ;
		Add(Y, X) ; Ind[X] ++ ;
	}
	for (int i = 1 ; i <= N ; i ++)
		if (! Ind[i]) { 
			Root = i ;
			Dfs(Root) ; break ; 
		}
	printf("%d", max(Dp[Root][0], Dp[Root][1])) ;
	return 0 ;
}
原文地址:https://www.cnblogs.com/sue_shallow/p/P1352.html