题意:
有n(n<=16000)个小镇,每两个小镇有且仅有一条路径相连。每个小镇有一个收益x(-1000<=x<=1000). 现在要求,选择一些小镇,满足下面两点要求: 1.选择的小镇都能互相到达,并且路径上的小镇也被选择了. 2.选择的小镇的收益和最大.
输入
一个整数n,接下来n个整数,代表这n个小镇的收益. 接下来n-1行,每行两个整数代表这两个小镇有道路直接相连.
输出
一个整数,代表最大的收益
Sample Input
5 -1 1 3 1 -1 4 1 1 3 1 2 4 5
Sample Output
4
嗯,这是棵树,然后我们可以乱搞了...
首先建一棵树。注意题目中指的是选一堆点,而不是一条路径上的所有点。
记录max1[i]为以i为根结点的子树下的最大解,max2[i]为以i为根节点的子树下过结点i的最大解。
max1初始值为最小值(INF),max2[i]初始值为v[i](因为必须要过结点i)。
然后dfs,max2[i]=Σmax2[k](i->k,max2[k]>=0),max1[i]=max{max1[k],max2[i]}(i->k)。因为以i为根结点子树中的最大解只可能在它儿子的子树中或过i的最大解中。#include <cstdio> #include <vector> #include <algorithm> using namespace std; const int MAXN = 16005, INF = -(1<<30); vector<int> e[MAXN]; int n = 0, v[MAXN] = {0}; int max1[MAXN] = {0}, max2[MAXN] = {0}; int vis[MAXN] = {0}, top = 0; void dfs(int cur) { int sum = 0; vis[cur] = ++top; for(int i = 0, lim = e[cur].size(); i < lim; ++i) if(!vis[e[cur][i]]) { dfs(e[cur][i]); if(max2[e[cur][i]] >= 0) sum += max2[e[cur][i]]; max1[cur] = max(max1[cur], max1[e[cur][i]]); } max2[cur] = max(max2[cur], sum+v[cur]); max1[cur] = max(max1[cur], sum+v[cur]); } int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%d", v+i); max1[i] = INF; max2[i] = v[i]; } for(int i = 1; i < n; ++i) { int x = 0, y = 0; scanf("%d%d", &x, &y); e[x].push_back(y); e[y].push_back(x); } dfs(1); printf("%d", max1[1]); return 0; }