P1122 最大子树和(树形动态规划)

题干在这里:https://www.luogu.org/problemnew/show/P1122

本题老师教了我两种方法,和大家分享一下,希望能帮到大家~~~

第一种思路:
由于每两个点之间都有一些联系,我们可以先把两两之间的关系用边的形式储存下来:

  1. head[x]是表示与x相连的第一个元素的下标
  2. edge[x].po是表示链头为x
  3. edge[x].next是表述链头是x,与x相连的元素的下标
  4. 运作方法:每读入一个数k,就将head[x]转变为k,之后再由edge数组转变下去,这样就将k与整个链连接起来了

动态规划总是要有状态转移方程的,我们用f[x]表示以x为根的最大价值数(其实就是题目中所谓的美丽指数,只不过这个名字太奇怪了。。。)。用g[x]表示以x为根,并且一定要取x的最大价值数
先考虑g[x]的状态转移方程:

value[x]+∑max(0,g[x]);

考虑f[x]是否取x:
如果不取,那么和他相连的子树都可以取,状态转移方程是(其中y具体取值请参看本人的代码):

max(f[y]);

而且一定要求两种情况的最大值!!!并且所有的f[x]d都要附一个足够小的数才行(本蒟蒻在这里卡了一个小时,望大家注意!!!)

当x是根的时候,需要用到它的子树列,用深搜就可以实现。深搜有两个参数:x表示处理的对象,fa表示该对象的父亲(之后是不能再回到fa的!!)

最后献上代码~~~

#include<iostream>
const int maxN=20000;
const int minvalue=-2147483647;
using namespace std;
struct node{
    int po,next;
} edge[2*maxN];

int head[maxN],n,a,b,value[maxN],tot,f[maxN],g[maxN];

void insert(int x,int y)
{
    edge[++tot].po=y;
    edge[tot].next=head[x];
    head[x]=tot;
}

void readin()
{
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>value[i]; 
    } 
    for(int i=1;i<n;++i){
        cin>>a>>b;
        insert(a,b);
        insert(b,a);
    }
} 

void dfs(int x,int fa){
    f[x]=minvalue;
    g[x]=value[x];
    int t=head[x];
    while (t!=0){
        int y=edge[t].po;
        if (y!=fa){         
            dfs(y,x);
            f[x]=max(f[x],f[y]);
            g[x]+=max(0,g[y]);
        }
        t=edge[t].next;
    }
    f[x]=max(f[x],g[x]);
} 

int main()
{
    readin();
    dfs(1,0);
    cout<<f[1]<<endl;
    return 0;
} 

第二种思路:
存储两数关系方法与第一种思路一样,连状态转移方程都一样,就是求最大价值数的方法不同,上面了深搜的方法,将我们需要的状态在需要的时候求出来。
这次的思路是:直接将所有的状态都求出来,再从后往前改变每个父节点的最大价值数,这个可以用宽搜来实现。

最后附上我的代码~~~

#include<iostream>
#include<cstring>
using namespace std;
const int minvalue=-2147483647;
const int maxN=200000;
struct node{
    int po,next;
}tree[2*maxN];
int n,head[maxN],a,b,tot,qwq=1;
int value[maxN],f[maxN][2],g[maxN],k[maxN];
bool panduan[maxN];

void insert(int x,int y)
{
    tree[++tot].po=y;
    tree[tot].next=head[x];
    head[x]=tot;
}

void readin()
{
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>value[i];
        g[i]=value[i];
        k[i]=minvalue;
    }
    for(int i=1;i<n;++i){
        cin>>a>>b;
        insert(a,b);
        insert(b,a);
    }
}

void bfs()
{
    memset(panduan,true,sizeof(panduan));
    f[1][0]=1;
    int st=1;
    while(st<=qwq){
        int t=head[f[st][0]];
        while(t!=0){
            int y=tree[t].po;
            if(y!=f[st][1]){
                panduan[f[st][0]]=false;
                qwq++;
                f[qwq][0]=y;
                f[qwq][1]=f[st][0];
            }
            t=tree[t].next;
        }
        st++;
    }
}

void work()
{
    for(int i=n;i>=1;--i){
        if(panduan[f[i][0]]==true)
            k[i]=value[i];
        g[f[i][1]]+=max(0,g[f[i][0]]);
        k[f[i][1]]=max(k[f[i][1]],k[f[i][0]]);
        k[f[i][1]]=max(g[f[i][1]],k[f[i][1]]);
    }
}

int main()
{
    readin();
    bfs();
    work();
    cout<<k[1]<<endl;
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/ljp946/article/details/81229756