Codeforces 486D Valid Sets
题意:
给定一棵树,任意选定两个节点(也可以是同一个节点),使这两个点和连接这两个点的路径上的点中最大值和最小值小于d
题解:
依次选定每一个节点并假设它是根节点(这棵树不一定是二叉树),同时假定根节点的值最大。从根节点开始遍历子节点,每一个子节点要满足以下性质:
- 子节点的值要小于等于根节点的值
- 子节点的值与根节点的值之差小于等于d
- 特别的,如果某一个子节点的值等于根节点,那么使这个子节点为根节点时就会发生重复。为了去除这一情况,从根节点向下遍历时,我们要求与根节点值相同的点的原序号要大于根节点的原序号
dfs函数的实现:
long long int sum; //包括当前节点的子树的数量
对于一个节点如果它自身不符合要求,返回0,否则sum=1(自己算一个)。遍历每一个子节点:如果子节点dfs返回0无子树,只有一种可能性--不选这个子节点,sum=1;如果子节点dfs返回大于零,两种可能性:选或不选,sum=(dfs(子节点)+1)
题解代码
#include <iostream>
#include <vector>
#include <cmath>
#define MOD ((ll)1e9+7)
using namespace std;
typedef long long int ll;
ll a[2010];
ll d,n;
vector<ll> node[2010];
ll dfs(ll pos,ll root,ll parent){ //dfs(Current node, Root node, Parent node)
if(a[pos]>a[root] || a[root]-a[pos]>d ||
(a[pos]==a[root]&&pos<root)){
return 0;
}
ll sum=1;
for(ll& i:node[pos]){
if(i!=parent){
sum*=(dfs(i,root,pos)+1);
sum%=MOD;
}
}
return sum;
}
int main(){
cin>>d>>n;
for(int i=1;i<=n;++i){
cin>>a[i];
}
for(int i=1;i<=n-1;++i){
int u,v;
cin>>u>>v;
node[u].push_back(v);
node[v].push_back(u);
}
ll sum=0;
for(int i=1;i<=n;++i){
ll t=dfs(i,i,0);
sum+=t;
sum%=MOD;
}
cout<<sum<<endl;
return 0;
}