JZOJ 3419. 【NOIP动态规划专题】最大利润

目录:


分析:

首先是用树形dp,这个小编就不废话了,小编将着重点放在动态方程上:
我们用 f [ i ] [ 1 ] 表示在i点开饭店, f [ i ] [ 0 ] 则相反,而我们就可以进行分类讨论了:
1) f [ i ] [ 1 ] = f [ t o ] [ 0 ] .即在i点开饭店时,我们的子节点都不能开饭店
2) f [ i ] [ 0 ] = m a x { f [ t o ] [ 0 ] , f [ t o ] [ 1 ] } .即当不在i点开饭店时,我们的子节点可以开可以不开,那我们就选择最优解


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
int f[100001][2],ls[100001],x[100001],c=0;
struct edg{
    int to,next;
}e[200001];
void add(int a,int b)
{
    e[++c]=(edg){b,ls[a]};
    ls[a]=c;
}
void dp(int a,int b)
{
    f[a][1]=x[a];
    f[a][0]=0;
    for(int i=ls[a];~i;i=e[i].next)
    {
        int to=e[i].to;
        if(to==b) continue;
        dp(to,a);
        f[a][1]+=f[to][0];
        f[a][0]+=max(f[to][1],f[to][0]);
    }
    return;
}
int main()
{    
    memset(ls,-1,sizeof ls);
    int n=read();
    for(int i=1;i<=n;i++) x[i]=read();
    int a,b;
    for(int i=1;i<n;i++)
    {
        a=read();b=read();
        add(a,b);add(b,a);//建邻接表
    }
    dp(1,0);
    printf("%d",max(f[1][0],f[1][1]));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35786326/article/details/80977585
今日推荐