Algorithm study notes: tree DP

Algorithm study notes: tree DP

1 Introduction

Tree DP is a kind of DP (nonsense) , specially used for DP on the tree.

This type of DP is very easy to understand because of its memorable board and conspicuous markings.

Moreover, the tree-shaped DP does not look like a DP, but more like a brute force search.

2. Detailed

Example: P1352 Prom without a boss

The title is actually to give a tree with nnFor a tree of n points, select some points so that these points are not adjacent to each other, and find the maximum point weight.

This is the problem of the tree DP board.

Save the tree first.

As mentioned in the preface: tree-shaped DP is more like a brute force search, so we need to do dfs on this tree again, side dfs side DP.

Considering that the tree-shaped DP is a kind of DP (isn't it) , we still need the basic routine of DP: set the state, infer the transition equation, infer the initial value, and find the answer.

All the following discussion assumes that the shape and root of the tree have been determined.

Let fk, 0/1 f_{k,0/1}fk,0/1Represents node kkk and the maximum weight sum of the points selected by its subtree. 0 00 means nodekkk hold on,1 11 means nodekkk put.

So as a tree DP, one very important point is: the ff of the parent nodeThe calculation of f is related to the child nodes.

So for this problem, our state transition equation is as follows:

f k , 0 = max ⁡ { f u , 0 , f u , 1 ∣ u ∈ V } f_{k,0}=\max\{f_{u,0},f_{u,1} | u \in V\} fk,0=max{ fto , 0,fu , 1uV }

f k , 1 = r k + max ⁡ { f u , 0 ∣ u ∈ V } f_{k,1}=r_k+\max\{f_{u,0} | u \in V\} fk,1=rk+max{ fto , 0uV }

Where VVV iskkA collection of sons of k .

If this point is not selected, then the son can choose or not; but if it is selected, then the son cannot choose.

Note: The selected point set U = ∅ U=\varnothingU= is also possible, so the possible answer is0 00

The final answer is froot, 0/1 f_{root,0/1}froot,0/1 The maximum value in.

Code:

#include <bits/stdc++.h>
#define Max(a, b) ((a > b) ? a : b)
using namespace std;

typedef long long LL;
const int MAXN = 6e3 + 10;
int n, r[MAXN], f[MAXN][2], root;
vector <int> Next[MAXN];
bool book[MAXN];

int read()
{
    
    
	int sum = 0, fh = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
	return sum * fh;
}

void dfs(int now, int fa)
{
    
    
	f[now][0] = 0, f[now][1] = r[now];
	for (int i = 0; i < Next[now].size(); ++i)
	{
    
    
		int u = Next[now][i];
		if (u == fa) continue;
		dfs(u, now);
		f[now][0] = Max(f[now][0], Max(f[now][0] + f[u][0], f[now][0] + f[u][1]));
		f[now][1] = Max(f[now][1], f[now][1] + f[u][0]);
	}
}

int main()
{
    
    
	n = read();
	for (int i = 1; i <= n; ++i) r[i] = read();
	for (int i = 1; i < n; ++i)
	{
    
    
		int x = read(), y = read(); book[x] = 1;
		Next[y].push_back(x); Next[x].push_back(y);
	}
	for (int i = 1; i <= n; ++i)
		if (!book[i]) {
    
    root = i; break;}
	dfs(root, root);
	printf("%d\n", Max(f[root][0], f[root][1]));
	return 0;
}

A tree-shaped DP board is provided here, but there is no guarantee that this board can pass all problems.

int f[...];

void dfs(int now, int fa...)
{
    
    
	/*设置初值*/
	for (/*遍历儿子*/)
	{
    
    
		int u = /*儿子*/;
		if (u == fa) continue;//注意不能返回父亲节点
		dfs(u, now...);
		/*转移*/
	}
}

3. Practice questions

Practice questions? Go go go go go first.

Guess you like

Origin blog.csdn.net/BWzhuzehao/article/details/114079227