没有上司的舞会
由于每个人(除了根节点)都有直接上司,所以我们可以把它看作一棵树
通过分析,我们不难看出这道题考的是树形动态规划( 树形 D P 树形DP 树形DP)
首先我们得先找到那个根节点, r o o t root root
我们可以把每个节点是否有直接上司存在一个数组 b o o k book book 中布尔值为 t r u e true true 表示节点 i i i 有上司,反之没有
int check()//返回值为根节点编号
{
for(int i=1;i<=n;i++)
{
if(book[i]==false)
{
return i;
}
}
}
bool book[MAXN];
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
book[v]=true;
}
root=check();
这时候,我们就需要分析一下本题的状态转移方程:
以一个数组 f [ M A X N ] [ 2 ] \tt f[MAXN][2] f[MAXN][2] 来表示状态
其中 f [ i ] [ 0 ] f[i][0] f[i][0] 表示以节点 i i i 为根节点的子树的最优快乐指数
状态转移方程:
f
[
i
]
[
0
]
=
(
∑
j
=
b
[
s
o
n
s
]
i
=
a
[
i
]
[
s
o
n
s
]
)
m
a
x
(
f
[
i
]
[
0
]
,
f
[
i
]
[
1
]
)
;
f
[
i
]
[
1
]
=
(
∑
j
=
b
[
s
o
n
s
]
i
=
a
[
i
]
[
s
o
n
s
]
)
+
w
[
i
]
\tt f[i][0]=\left(\sum^{i=a[i][sons]}_{j=b[sons]}\right)max(f[i][0],f[i][1]); \tt f[i][1]=\left(\sum^{i=a[i][sons]}_{j=b[sons]} \right) + w[i]
f[i][0]=
j=b[sons]∑i=a[i][sons]
max(f[i][0],f[i][1]);f[i][1]=
j=b[sons]∑i=a[i][sons]
+w[i]
我们可以用一个深搜 d f s dfs dfs 来遍历整棵树
每次搜索以一个节点为跟的子树,搜到叶子节点后回溯,更新动规需要使用到的son
深搜代码:
void dfs(int u)
{
f[u][1]=w[u];
for(int i=0;i<b[u];i++)
{
int son=a[u][i];
dfs(son);
f[u][0]+=max(f[son][0],f[son][1]);
f[u][1]+=f[son][0];
}
return;
}
完整版代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=6*1e3+5;
int n,f[MAXN][2],b[MAXN],w[MAXN];
vector<int> a[MAXN];
int root;
bool book[MAXN];
int check()
{
for(int i=1;i<=n;i++)
{
if(book[i]==false)
{
return i;
}
}
}
void dfs(int u)
{
f[u][1]=w[u];
for(int i=0;i<b[u];i++)
{
int son=a[u][i];
dfs(son);
f[u][0]+=max(f[son][0],f[son][1]);
f[u][1]+=f[son][0];
}
return;
}
int u,v;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
a[v].push_back(u);
b[v]++;
book[u]=true;
}
root=check();
dfs(root);
printf("%d\n",max(f[root][0],f[root][1]));
return 0;
}