P1122最大子树和

P1122最大子树和
题意:一株奇怪的花卉,上面共连有N朵花,共有N-1条枝干将花儿连在一起,并且未修剪时每朵花都不是孤立的。每朵花都有一个“美丽指数”,该数越大说明这朵花越漂亮,也有“美丽指数”为负数的,说明这朵花看着都让人恶心。所谓“修剪”,意为:去掉其中的一条枝条,这样一株花就成了两株,扔掉其中一株。经过一系列“修剪“之后,还剩下最后一株花(也可能是一朵)。要求:通过一系列“修剪”(也可以什么“修剪”都不进行),使剩下的那株(那朵)花卉上所有花朵的“美丽指数”之和最大。

以为只是一个简单的树,做了半天也没思路,看了别人的方法才知道是树形DP,还用到了图里的链式前向星,知识盲区(=_=)。
分析:题意就是求以每个点为根的子树大小,找最大值,用 f[x] 表示以 x 为根且包含 x 的最大权联通块,状态转移方程为f[p]+=max(0,f[k])(k 为p 的儿子,排除负数),求每一个点为根,用dfs实现。
补充: 建树我们用到图的知识。
链式前向星存图如下:u表示结点,h[u]用来定位u的第一条边,t[i].to存u的邻居结点,t[i].next定位u的下一条边指向的邻居结点的位置。例如:u=7时,h[u]=12,即结点7的第一条边连接的邻居结点存在i=12这个位置,t[12].to=6,表示结点7的第一个邻居是结点6,t[12].next=10,即结点7的第二条边连接的邻居结点存在i=10这个位置里,t[10].to=5,即结点7的第二个邻居结点是5,依次类推,直到t[i].next=0时停止。
在这里插入图片描述
代码实现:

const int N=16000;
struct n
{
    
    
    int to,next;
   // int w;可以增加一个变量表示结点权值
}t[2*N];
int h[2*N],p=1;
void add(int u,int v)//可加第三个参数int w,即权值
{
    
    
    t[p].to=v;
    //t[p].w=w;
    t[p].next=h[u];
    h[u]=p++;
}
//遍历结点i的所有邻居
for(int  i=h[u];i;i=t[i].next)
{
    
    ...}

dfs实现过程图解:
在这里插入图片描述
只能AC90%的代码

#include<iostream>
#include<algorithm>
using namespace std;
struct n
{
    
    
    int to,next;
}t[100000];
int p=1,n,a[100000],f[100000],h[100000],x,y,ans=0;
void add(int u,int v)
{
    
    
    t[p].to=v;
    t[p].next=h[u];
    h[u]=p++;
}
void dfs(int p,int father)
{
    
    
    f[p]=a[p];
    for(int i=h[p];i;i=t[i].next)
    {
    
    
        int k=t[i].to;
        if(k!=father)
        {
    
    
            dfs(k,p);
            f[p]+=max(0,f[k]);
        }
    }
    ans=max(ans,f[p]);
}
int main()
{
    
    
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n-1;i++)
    {
    
    
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_51443397/article/details/121116010