【树形DP】JZOJ-3419|最大利润

前言

题目那里因为CSDN炸了,所以没打空格

题目大意

n 个点,在每个点开店有一定的利润,但是这个点卡了店与它相邻的点都不能开,求最大利润。

解题思路

树形DP
f [ i ] 表示第 i 个点开店的最大利润, g [ i ] 表示第 i 个点不开店的利润,显然根据题意,我们可以列出方程

f [ i ] = d [ i ] + j = 1 1.. i s u m g [ s o n ]

g [ i ] = j = 1 j = 1.. i s u m m a x { g [ s o n ] , f [ s o n ] }

意思就是这个点开店的话,就加上与它相邻的点不开店的最大利润,如果这个店不开店的话,就加上与它相邻的点开店的最大利润

代码

#pragma GCC optimize(2)
#pragma once

#include<cstdio>
#include<cstring>
#define max(a,b) a>b?a:b
using namespace std;
int f[100001],d[100001],g[100001],n,l[100001],tot;
struct node{int next,to;}e[200001];//邻接表
bool vis[100001];//判断是否走过
void add(int u,int v)//建边
{
    e[tot]=(node){l[u],v};l[u]=tot++;
    return;
}
void dfs(int x)
{
    vis[x]=true;//这个点已走过
    f[x]+=d[x];//初始化
    g[x]=0;//初始化
    for(int i=l[x];~i;i=e[i].next)
    {
        int y=e[i].to;
        if(vis[y]) continue;//求过了就不必再求了
        dfs(y);//继续遍历
        g[x]+=max(f[y],g[y]);//动态转移
        f[x]+=g[y];
    }
}
int main()
{
    memset(l,-1,sizeof(l));
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&d[i]);//输入
    for(int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);//建边
    }
    dfs(1);
    printf("%d",max(f[1],g[1]));//输出
}

时间复杂度

因为每个点只会被遍历一次,所以时间复杂度是 O ( n )

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/80979755
今日推荐