[Tree dp] | AcWing algorithm basic class test questions summary

285. A Prom Without a Boss

Title description

A company has N employees, numbered 1~N.
Their relationship is like a tree rooted by the principal, and the parent node is the direct boss of the child node.
Each employee has a happiness index, which is given by an integer Hi, where 1≤i≤N.
Now there is an anniversary banquet, but no staff is willing to attend the meeting with their direct supervisors.
Under the premise that this condition is met, the organizer hopes to invite some staff to participate in the conference, so that the sum of the happiness index of all the staff participating in the conference is maximized.

Input format
An integer N in the first line.
In the next N rows, the i-th row represents the happiness index Hi of employee i.
In the next line N-1, enter a pair of integers L and K in each line, indicating that K is L's direct boss.

Output format
Output the largest happiness index.

Data range
1≤N≤6000,
−128≤Hi≤127

Input sample:

7
1
1
1
1
1
1
1
1 3 //That is, 3->1
2 3
6 4
7 4
4 5
3 5

Sample output:

5

analysis

The employees of the entire company form a tree, and each employee is a node on the tree. For each node, there are two states of 0 and 1. Selected is 1 and unselected is 0.

State representation:

f[u][0]: The subtree rooted at the node u, and the various solutions that meet the requirements
f[u][1]at the point u are not selected: the subtree rooted at the node u, and the various solutions that meet the requirements at the point u are selected

Attribute: Max, f[u][0]or f[u][1]the value is the maximum value of various solutions that meet the requirements

Find the maximum value of the scheme that the subtree from the u node meets the requirements. The final result must be selected in the f[u][0]sum f[u][1], and the maximum value is selected.

  1. Consider whether to choose node u
  2. Recursively consider each child node s i of the parent node u , and the condition for the end of the recursion is to reach the leaf node.

Consider the parent node u as the root node and the child node s as the root node. The two methods are the same and independent of each other .
And the value of the parent node needs to use the value of the child node.

Assuming that the subtree with node u as the root node has multiple child nodes s i , considering each of its child nodes s i , it can be regarded as a sub-subtree with child node s i as the root.

  1. If the node u is selected, the child node s i must not be selected.
    f [u] [1] = ∑ (f [si, 0]) f[u][1]=∑(f[si,0])f[u][1]=(f[si,0])
  2. If the node u is not selected, the sub-nodes can be selected or not, just select the maximum value among them.
    f [u] [0] = ∑ max (f [si, 0], f [si, 1]) f[u][0]=∑max(f[si,0],f[si,1])f[u][0]=m a x ( f [ s i ,0],f[si,1])

Note:
From the input of the data, we don't know who the root node of the tree is, so we need to process it ourselves.
After the root node root is obtained, it is regarded as a subtree of the root node, so in the end, only whether the root root node is selected, f[root][0]and f[root][1]the larger of the output sum can be output .

Code

#include <iostream>
#include <cstring>
#define read(x) scanf("%d",&x)

using namespace std;

const int N=6010;
int hpy[N];
int h[N],e[N],ne[N],idx;//树,N个顶点,N-1条边
//next数组记录后继结点,通过idx记录
int pre[N];//pre数组记录前驱结点,直接通过结点编号记录
int dp[N][2];

void add(int a,int b)//a->b的边
{
    
    
    e[idx]=b,ne[idx]=h[a],h[a]=idx++; 
    pre[b]=a;
}

void dfs(int u) //判断以该点为根的子树的最大happy值
{
    
    
  "初始化,是否选该结点:dp[u][1]和dp[u][0]"
  "选中该结点,加上该happ值,不选中时,dp[u][0]=0"
    dp[u][1]=hpy[u];   
  "递归结束的条件,遇到叶子结点,它没有子节点了。只进行初始化,然后就往上返回"
    for (int i=h[u];~i;i=ne[i]) {
    
    
        int j=e[i]; //找它的子节点
        dfs(j); //求子节点的最大happy值
        //考虑以u为根的子树,是否选子节点?
        dp[u][0]+=max(dp[j][0],dp[j][1]); //不选u时,子节点可选可不选,取最大值。
        dp[u][1]+=dp[j][0]; //选u时,子节点必不能选。
    }
}

int main()
{
    
    
    memset(h,-1,sizeof h);
    int n;
    read(n);
    for (int i=1;i<=n;i++) read(hpy[i]);
    //存树
    int l,k; //k是l的直接上司,即k->l的边
    for (int i=1;i < n;i++) {
    
     //n个顶点,所以共n-1条边,不能取等号
        read(l),read(k);//先输入的是子节点
        add(k,l);  //存数k->l的边
    }
    //找树的根节点,记录结点编号,只有根节点没有父结点,pre[rt]==0
    int rt=1;
    while (pre[rt]) rt++;
    dfs(rt);
    int res=max(dp[rt][0],dp[rt][1]);
    printf("%d",res);
    
    return 0;
}

Be sure to remember the initialization in the first line of the main loop, which often makes mistakes.

In dfs recursion, the condition for the end of the recursion is to meet the leaf node. Since there are no child nodes, it will not enter the for loop. After initialization, it returns up.

The tree structure does not exist for a point with multiple in-degrees, only one in-degree and at most one out-degree, which ensures that each point will only be initialized once and will only experience one recursion.

Guess you like

Origin blog.csdn.net/HangHug_L/article/details/114537073