[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 ;
}
posted @ 2018-12-26 17:45  Sue_Shallow  阅读(133)  评论(0编辑  收藏  举报
Live2D