p1302

开学啦!又开始了苦逼的生活,完全没有放假够啊。

还是来看题吧……

样例输入 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;
}

 

posted @ 2018-09-01 13:42  zzuqy  阅读(102)  评论(0编辑  收藏  举报