0x10 题目链接
0x20 题目描述
0x21 Tag
树形DP
0x22 题面
0x30 思路与算法
树形DP!
这应该是我博客里第一次提及树形DP。对于本题,可以大致地将其抽象成一个决策树的模型:对于每一个节点,我们可以选择选或者不选,即数组的第二维设置[0]或[1]。
从根节点
r
o
o
t
root
root开始深搜,如果选了该节点,其子节点一定不可以被选择;而如果不选择该节点,则要选出选与不选子节点贡献的快乐度的最大值。
以上我们可以推出状态转移方程
f
(
x
,
1
)
=
a
[
i
]
+
f
(
x
.
c
h
i
l
d
,
0
)
f(x,1)=a[i]+f(x.child,0)
f(x,1)=a[i]+f(x.child,0)
f
(
x
,
0
)
=
m
a
x
(
(
x
.
c
h
i
l
d
,
0
)
,
f
(
x
.
c
h
i
l
d
,
1
)
)
f(x,0)=max((x.child,0),f(x.child,1))
f(x,0)=max((x.child,0),f(x.child,1))
其中, a [ i ] a[i] a[i]表示选择x节点之后增加的快乐值。
f ( x , 1 ) f(x,1) f(x,1)表示选择该节点 f ( x , 0 ) f(x,0) f(x,0)表示不选该节点
0x40 代码实现
0x41 代码细节
存图
struct Edge
{
int to, w, next;
}edges[MAXN];
int head[MAXN], cnt;
inline void add(int from, int to, int w=1)
{
edges[++cnt].w = w;
edges[cnt].to = to;
edges[cnt].next = head[from];
head[from] = cnt;
}
将树以图的形式存入图中,edges[eg].to
表示孩子节点。
判断根节点
int root=0;
for(int i=1;i<=n;++i)
if(rt[i]) root=i;
在输入的时候保存其父节点,如果没有保存父节点,则该节点为根节点
0x42 完整代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 998244353;
const ll INF = 0x3f3f3f3f;
// <------------------------------->
#define endl "\n"
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define HACK freopen("test.in", "r", stdin);freopen("test.out", "w", stdout);
#define RT double rtime = 1.0 * clock() / CLOCKS_PER_SEC;cout<<"\nRuntime: "<<rtime<< " s.\n";
#define debug(x) cout<<#x<<": "<<x<<endl
#define debug_arr(arr) cout<<#arr<<": "<<endl; for(auto x:arr) cout<<x<<" "; cout<<"\n"
// <------------------------------->
const int MAXN=6e3+5;
int n;
int a[MAXN],dp[MAXN][2];
bool rt[MAXN];
struct Edge
{
int to, w, next;
}edges[MAXN];
int head[MAXN], cnt;
inline void add(int from, int to, int w=1)
{
edges[++cnt].w = w;
edges[cnt].to = to;
edges[cnt].next = head[from];
head[from] = cnt;
}
void dfs(int cur)
{
for(int eg=head[cur];eg!=0;eg=edges[eg].next)
{
int to=edges[eg].to;
dfs(to);
dp[cur][1]+=dp[to][0];
dp[cur][0]+=max(dp[to][0],dp[to][1]);
}
dp[cur][1]+=a[cur];
}
int main()
{
IOS;
#ifdef LOCAL_JUDGE
HACK;
#endif
memset(rt,1,sizeof rt);
int n;
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>a[i];
}
for(int i=1;i<n;++i)
{
int u,v;
cin>>u>>v;
rt[u]=0;
add(v,u);
}
int root=0;
for(int i=1;i<=n;++i)
if(rt[i]) root=i;
dfs(root);
cout<<max(dp[root][0],dp[root][1]);
#ifdef LOCAL_JUDGE
RT;
#endif
return 0;
}
0x50 另
一道最入门的树形DP
代码仅为个人答案,若有错误欢迎指正 =)