开学啦!又开始了苦逼的生活,完全没有放假够啊。
还是来看题吧……
样例输入 Sample Input 6 10 20 25 40 30 30 4 5 1 3 3 4 2 3 6 4 样例输出 Sample Output 90
一道正常的树上dp。
为什么是树呢?题目中提示的非常清楚了,n个节点n-1条边,每个点都有边,不是树还能是什么?
为什么是dp呢?假如我知道了子节点们的各种数据,那我可以在很短时间内计算出这个节点的数据,叶子节点的数据还巨好求。
怎么dp呢?这道题是有一点点后效性的,选与不选都会影响到父节点的选取,那就多一个维度好了,反正不多。
我们维护ans1[i]表示选取i节点的最大值,ans0[i]表示不选的最大值。选取的时候只能把子节点的ans0加上,但是可以加上自己的权值。ans0就宽松一些,可以选取子节点ans0和ans1最大的那个,但是不能加上自己的权值了。
在读入边的时候要弄成无向边,那么dfs的时候就要用一个falg数组判断是否经历过了,因为子节点有时候也会指向父节点的。
using namespace std; int i,f,k,tx,ty; int n; int ans1[100010],ans0[100010],v[100010]; int tot,link[100010]; bool flag[100010]; struct node { int x,y,next; }o[200010]; void add(int x,int y) { tot++; o[tot].x=x; o[tot].y=y; o[tot].next=link[x]; link[x]=tot; } void dfs(int now) { flag[now]=1; for(int j=link[now];j!=0;j=o[j].next) { if(flag[o[j].y])continue; dfs(o[j].y); ans1[now]+=ans0[o[j].y]; ans0[now]+=max(ans0[o[j].y],ans1[o[j].y]); } ans1[now]+=v[now]; return ; } int main() { ios::sync_with_stdio(false); //freopen("123.in","r",stdin); //freopen("123.out","w",stdout); cin>>n; for(i=1;i<=n;i++) cin>>v[i]; for(i=1;i<n;i++) { cin>>tx>>ty; add(tx,ty); add(ty,tx); } dfs(1); cout<<max(ans1[1],ans0[1]); return 0; }