洛谷 P1352 没有上司的舞会

洛谷 P1352 没有上司的舞会

思路

一道入门的简单的树形(DP)
我们用(is)数组来表示这个点是不是根节点
如果他有上司,就绝对不是根节点了
因为这是一棵树,所以只会有一个人没有上司,而他就是根节点
然后考虑如何进行(DP),我们用(f[x][0/1])表示只考虑以(x)点为根的子树,且(x)号点有/没有被选择,被选择的点的权值和的最大值。
(x)点的儿子构成的集合为(son_x) ,转移考虑 (x)点选不选。
显然转移方程为

[f[x][0] = sum y∈son_x max(f[y][0],f[y][1]) ]

[f[x][1] = sum y∈son_x f[y][0] ]

最后的答案为(max{f(root,0),f(root,1)})//(root)就是根节点

代码

//知识点:树形DP 
/*
By:Loceaner
*/
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	return x * f;
}

const int N = 6e3 + 11;

vector <int> e[N];
int ans;//ans记录答案 
int n, f[N][2], is[N], vis[N]; 
//f[x][0/1]表示只考虑以 x 点为根的子树,且 x 号点有/没有被选择,被选择的点的权值和的最大值。
//is[i]用来判断是否为根节点,vis[i]表示是否访问过 

void dfs(int x) {
	vis[x] = 1;
	for(int i = 0; i < (int)e[x].size(); i++) {
		int to = e[x][i];
		if(vis[to]) continue;
		dfs(to);
		f[x][1] += f[to][0];
		f[x][0] += max(f[to][0], f[to][1]);
	}
	return;
}

int main() {
	n = read();
	for(int i = 1; i <= n; i++) f[i][1] = read();//一开始输入的就是选i的快乐值 
	for(int i = 1, l, k; i < n; i++) {
		l = read(), k = read();
		is[l] = 1;//肯定不是根节点 
		e[k].push_back(l);
	}
	scanf("0 0");
	for(int i = 1; i <= n; i++) {
		if(!is[i]) {//is数组中没有被访问过的便是根节点 
			dfs(i); 
			ans = max(f[i][0], f[i][1]);
			cout << ans << '
';
			return 0;
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/loceaner/p/11673810.html