洛谷 P1122 最大子树和 题解

题目:P1122 最大子树和

DP - 树形DP - dfs

这题的做法被题目名字给暴露了

f [ i ] f[i] 为以点 i i 为根的子树中的最大子树和

j j i i 的子节点,则转移方程为: f [ i ] = m a x { f [ j ] × [ f [ j ] > 0 ] + a [ i ] , m a x { f [ j ] } , a [ i ] } f[i]=max\{ \sum f[j]\times[f[j]>0]+a[i],max\{f[j]\} , a[i]\}

后来发现错了,因为 f [ i ] f[i] 求出来的时候不一定包括了节点 i i ,也就是说点 i i 可能已经被剪掉了


下面是正解:

f [ i ] f[i] 为以点 i i 为根的最大子树和

转移方程: f [ i ] = f [ j ] × [ f [ j ] > 0 ] + a [ i ] f[i]=\sum f[j] \times [f[j]>0]+a[i]

#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
const int Maxn=16000+20,inf=0x3f3f3f3f;
int a[Maxn],f[Maxn];
int n,ans;
vector <int> e[Maxn];
void dfs(int x,int fa)
{
	int tot=a[x];
	for(int i=0;i<e[x].size();++i)
	{
		int y=e[x][i];
		if(y==fa)continue;
		dfs(y,x);
		if(f[y]>0)tot+=f[y];
	}
	f[x]=tot;
	ans=max(ans,tot);
}
int main()
{
//	freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	scanf("%d",a+i);
	for(int i=1;i<n;++i)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(1,0);
	printf("%d\n",ans);
	return 0;
}

发布了75 篇原创文章 · 获赞 2 · 访问量 1810

猜你喜欢

转载自blog.csdn.net/Brian_Pan_/article/details/103959270