P8625 [蓝桥杯 2015 省 B] 生命之树
题目:
链接:https://www.luogu.com.cn/problem/P8625
基本思路:
1.使用dp[N]记录i节点的当前最大值
2.使用vector
3.使用vis[N]防回退
如果该节点没有子节点,那么这个点的最大值就记录为当前的值:val
如果该节点有子节点,那么先遍历子节点,然后+res并记录
由于使用了vis,那么就保证不会出现重复加和某一树节点的情况,所以不用减去某个树叶的值
证明:如果k节点的子节点j最大值是大于0,
1.当k节点<0时,j节点的max不用加val[k],会遍历到dp[j];
2.当k节点>0,j节点max加上val[k]存在dp[k]中。
所以一定不用减去
代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
typedef long long ll;
using namespace std;
const int N = 1e5 + 2;
ll val[N];
int n;
ll dp[N];
vector<int>nex[N];
bool vis[N];
ll dfs(int k)
{
//k:point
vis[k] = 1;
if (dp[k]!=0)return dp[k];
ll res = val[k];
if (nex[k].size() == 0)res = val[k];
else
for (int i = 0; i < nex[k].size(); i++)
if (!vis[nex[k][i]] and dfs(nex[k][i]) >= 0)
{
res = res + dfs(nex[k][i]);
}
return dp[k] = res;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)cin >> val[i];
int from, to;
for (int i = 0; i < n - 1; i++) { cin >> from >> to; nex[from].push_back(to); nex[to].push_back(from); }
ll maxn = 0;
for (int i = 1; i <= n; i++)
maxn = max(dfs(i), maxn);//按序遍历,怎么遍历都行
cout << maxn;
return 0;
}