【NOIP practice】BSOJ 2265 最大利润 树形动规

29 篇文章 0 订阅
4 篇文章 0 订阅
2265 -- 【模拟试题】最大利润
Description
  政府邀请了你在火车站开饭店,但不允许同时在两个相连的火车站开。任意两个火车站有且只有一条路径,每个火车站最多有50个和它相连接的火车站。
  告诉你每个火车站的利润,问你可以获得的最大利润为多少?
Input
  第一行输入整数N(<=100000),表示有N个火车站,分别用1,2,……..,N来编号。接下来N行,每行一个整数表示每个站点的利润,接下来N-1行描述火车站网络,每行两个整数,表示相连接的两个站点。
Output
  输出一个整数表示可以获得的最大利润。
Sample Input
6
10
20
25
40
30
30
4 5
4 6
3 4
1 3
2 3
Sample Output

90


树形动规,f[point][bool_flag]表示取或不取当前点的时候取得的最大利润。

状态转移方程:

f[v][1]+=f[to][0];
f[v][0]+=max(f[son][1],f[son][0]);

注意要建双向边,DP时随便找一个点开始即可。

另外,DP传一个参数father_point来保证不走成环了。

#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
int n,M;
int fa[600005]={0},val[600005]={0},f[600005][2]={0};
struct Edge
{
	int next,to;
}w[1000005];
int cnt=0,h[100005]={0};
void Addarc(int x,int y)
{
	cnt++;w[cnt].to=y;w[cnt].next=h[x];h[x]=cnt;
}
void DP(int v,int fa)
{
	f[v][1]=val[v];
	f[v][0]=0;
	for(int i=h[v];i;i=w[i].next)
	{
		int to=w[i].to;
		if(to==fa)continue;
		DP(to,v);
		f[v][1]+=f[to][0];//要这个点,就不能要儿子 
		f[v][0]+=max(f[to][1],f[to][0]);//不要这个点,可要也可不要儿子,因为存在负的欢乐值。 
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",val+i);
	for(int i=1;i<n;i++)
	{
		int K,L;
		scanf("%d%d",&L,&K);
		Addarc(K,L);
		Addarc(L,K);
	}
	DP(1,0);
	printf("%d",max(f[1][1],f[1][0]));
	return 0;
}

另外,与这个相似的题有:

没有上司的聚会  (建的是单向边)

以及:

选课 和 二叉苹果树 (分组背包)

和:

加分二叉树  (基础题)


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值