[CF486D] Valid Sets - 树形dp
Posted mollnn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF486D] Valid Sets - 树形dp相关的知识,希望对你有一定的参考价值。
Description
给定一棵带点权的树,求满足点权极差不超过 (d) 的连通子图的个数。(n,d le 2000)。
Solution
枚举每个点作为最大值 (M),那么此时只有点权 (ge M-d) 的点是可以被考虑的。
树形 dp,设 (f[p]) 表示以当前选择的最大值点为根的情况下,(p) 的子树内,选取一个包含 (p) 的非空连通子图的方案数。
转移时,对于 (p) 的孩子 (q_1,q_2,...,q_k),依次枚举并更新 (f[p]),即 (f[p] leftarrow f[p] + f[p] f[q_i])。
注意点权是可以重复的,这样统计会造成重复计算,我们必须要构造点之间的严格全序关系,因此当点权相等时,比较编号大小即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2005;
const int mod = 1e+9+7;
vector <int> g[N];
int n,d;
int vis[N];
int val[N];
int f[N];
int maxVertex; // 枚举的最大点
void dfs(int p)
{
vis[p]=1;
if(val[p]==val[maxVertex])
{
// 权值相等,p 的序号必须更小
if(p>maxVertex) return;
}
else if(val[p]>val[maxVertex])
{
return;
}
else
{
// 权值不等,必须满足限制条件
if(val[p]<val[maxVertex]-d) return;
}
// 设定边界值
f[p]=1; // 选自己
// 处理孩子
for(int q:g[p])
{
if(!vis[q])
{
dfs(q);
f[p]=(f[p]+f[p]*f[q])%mod;
}
}
}
signed main()
{
cin>>d>>n;
for(int i=1;i<=n;i++)
{
cin>>val[i];
}
for(int i=1;i<n;i++)
{
int t1,t2;
cin>>t1>>t2;
g[t1].push_back(t2);
g[t2].push_back(t1);
}
int ans=0; // 总答案
for(int i=1;i<=n;i++)
{
// 处理 i 为 maxVertex 的情况
maxVertex=i;
fill(f+1,f+n+1,0);
fill(vis+1,vis+n+1,0);
dfs(maxVertex);
ans+=f[maxVertex];
ans%=mod;
}
cout<<ans<<endl;
return 0;
}
以上是关于[CF486D] Valid Sets - 树形dp的主要内容,如果未能解决你的问题,请参考以下文章