码迷,mamicode.com
首页 > 其他好文 > 详细

[CF486D] Valid Sets - 树形dp

时间:2020-10-19 22:25:22      阅读:18      评论:0      收藏:0      [点我收藏+]

标签:最大值   枚举   std   sign   相等   tor   选择   +=   转移   

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

标签:最大值   枚举   std   sign   相等   tor   选择   +=   转移   

原文地址:https://www.cnblogs.com/mollnn/p/13838385.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!