洛谷 P1352 没有上司的舞会 经典树形dp 类似于leetcode打家劫舍那题 树上取点集最值

题目描述

某大学有 nnn 个职员,编号为 1…n1\ldots n1…n。

他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。

现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 rir_iri​,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。

所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入格式

输入的第一行是一个整数 nnn。

第 222 到第 (n+1)(n + 1)(n+1) 行,每行一个整数,第 (i+1)(i+1)(i+1) 行的整数表示 iii 号职员的快乐指数 rir_iri​。

第 (n+2)(n + 2)(n+2) 到第 2n2n2n 行,每行输入一对整数 l,kl, kl,k,代表 kkk 是 lll 的直接上司。
输出格式

输出一行一个整数代表最大的快乐指数。
输入输出样例
输入 #1

7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5

输出 #1

5

说明/提示
数据规模与约定

对于 100%100%100% 的数据,保证 1≤n≤6×1031\leq n \leq 6 \times 10^31≤n≤6×103,−128≤ri≤127-128 \leq r_i\leq 127−128≤ri​≤127,1≤l,k≤n1 \leq l, k \leq n1≤l,k≤n,且给出的关系一定是一棵树。


基础树形dp 类似于打家劫舍那道题

定义状态 :

  • dp[i][0]表示选择节点i的最优值
  • dp[i][1]表示不选节点i的最优值

转移方程 :

  • d p [ i ] [ 0 ] = m a x ( d p [ i ] [ 0 ] , d p [ i ] [ 0 ] + d p [ j ] [ 1 ] ) 选 了 i 就 不 能 选 i 的 子 节 点 dp[i][0]=max(dp[i][0],dp[i][0]+dp[j][1])\\选了i就不能选i的子节点 dp[i][0]=max(dp[i][0],dp[i][0]+dp[j][1])ii
  • d p [ i ] [ 1 ] = dp[i][1]= dp[i][1]= m a x ( d p [ i ] [ 1 ] , d p [ j ] [ 1 ] , d p [ j ] [ 0 ] ,                            d p [ i ] [ 1 ] + d p [ j ] [ 1 ] , d p [ i ] [ 1 ] + d p [ j ] [ 0 ] ) max(dp[i][1],dp[j][1],dp[j][0],\\ ~~~~~~~~~~~~~~~~~~~~~~~~~~dp[i][1]+dp[j][1],dp[i][1]+dp[j][0]) max(dp[i][1],dp[j][1],dp[j][0],                          dp[i][1]+dp[j][1],dp[i][1]+dp[j][0])
    如果不选i,则可以选或不选i 的子节点,也可只要其中一个或多个子节点

边界条件 :

  • d p [ i ] [ 0 ] = w [ i ] dp[i][0]=w[i] dp[i][0]=w[i]当选择一个节点V,至少有w[V]的权值

#define debug
#ifdef debug
#include <time.h>
#endif

#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>

#define MAXN ((int)1e5+7)
#define ll long long int
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)

using namespace std;

#define show(x...) \
	do { \
	   cout << "\033[31;1m " << #x << " -> "; \
	   err(x); \
	} while (0)

void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }

namespace FastIO{

	char print_f[105];
	void read() {}
	void print() { putchar('\n'); }

	template <typename T, typename... T2>
	   inline void read(T &x, T2 &... oth) {
		   x = 0;
		   char ch = getchar();
		   ll f = 1;
		   while (!isdigit(ch)) {
			   if (ch == '-') f *= -1; 
			   ch = getchar();
		   }
		   while (isdigit(ch)) {
			   x = x * 10 + ch - 48;
			   ch = getchar();
		   }
		   x *= f;
		   read(oth...);
	   }
	template <typename T, typename... T2>
	   inline void print(T x, T2... oth) {
		   ll p3=-1;
		   if(x<0) putchar('-'), x=-x;
		   do{
				print_f[++p3] = x%10 + 48;
		   } while(x/=10);
		   while(p3>=0) putchar(print_f[p3--]);
		   putchar(' ');
		   print(oth...);
	   }
} // namespace FastIO
using FastIO::print;
using FastIO::read;

int n, m, Q, K, w[MAXN], vis[MAXN], dp[MAXN][2];

vector<int> G[MAXN];

// dp[i][0] 选 i 
// dp[i][1] 不选 i 
void dfs(int u) {
	if(G[u].empty()) {
		dp[u][0] = w[u];
		return ;
	}
	dp[u][0] = w[u];
	for(auto v : G[u]) {
		dfs(v);
		dp[u][0] = max({ dp[u][0], dp[u][0]+dp[v][1] }); 
		dp[u][1] = max({ dp[u][1], dp[v][0], dp[v][1], 
				     		dp[u][1]+dp[v][0], dp[u][1]+dp[v][1] });
	}
}

signed main() {
#ifdef debug
	freopen("test.txt", "r", stdin);
	clock_t stime = clock();
#endif
	read(n);
	for(int i=1; i<=n; i++) read(w[i]);
	for(int i=1; i<n; i++) {
		int chl, fat;
		read(chl, fat);
		vis[chl] = true;
		G[fat].push_back(chl);
	}
	int root = 0;
	for (int i=1; i<=n && !root; i++) 
		root = (vis[i] ? 0 : i);
	dfs(root);
	printf("%d\n", max(dp[root][0], dp[root][1]));
	





#ifdef debug
   clock_t etime = clock();
   printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif 
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值