树上跳跃

题目描述
懒惰的温温今天上班也在偷懒。盯着窗外发呆的温温发现,透过窗户正巧能看到一棵n个节点的树。一棵n个节点的树包含n-1条边,且n个节点是联通的。树上两点之间的距离即两点之间的最短路径包含的边数。
温温瞧见树上有一只灵活的小松鼠正在节点间跳来跳去。观察了很长一段时间之后,温温发现:松鼠每次跳跃,从当前节点可以跳到任何与当前节点距离不超过k的节点。
突发奇想的温温想要知道,如果定义f(u, v)为从松鼠从u点到v点所需的最少跳跃次数,那么,对于树上的所有点对(u, v),f(u, v)的总和是多少。
注意:(u, v)和(v, u)视作同一个点对,只计算一次答案。

输入
第一行两个整数n和k。
接下来n-1行每行两个整数ai, bi,表示节点ai和bi之间存在一条边。

1 ≤ k ≤ 5
2 ≤ n ≤ 5000 for 40%
2 ≤ n ≤ 200000 for 100%

输出

输出一个整数,表示所求的f(u, v)总和。

样例输入 Copy
【样例1】

6 2
1 2
1 3
2 4
2 5
4 6

【样例2】

13 3
1 2
3 2
4 2
5 2
3 6
10 6
6 7
6 13
5 8
5 9
9 11
11 12

样例输出 Copy
【样例1】

20

【样例2】

114

#include <bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int N = 2e5 + 10 ;
int e[N << 1] , ne[N << 1] , h[N << 1]  , idx , flow[N] , in[N] , dp[N][6] , size[N] , k , b[6] , n ;
void add(int a, int b)
{
    e[idx] = b , ne[idx] = h[a] , h[a] = idx ++ ;
}
void dfs1(int u , int fa)
{
    memset(b , 0 , sizeof b) ;
    if(fa)
     {
       b[0] = dp[fa][0] - dp[u][k - 1] - size[u] ;
       for(int i = 1; i < k ;i ++) b[i] = dp[fa][i] - dp[u][i - 1] ;
     }
    dp[u][0] += b[k - 1] + n - size[u] ;
    for(int i = 1 ; i < k ;i ++) dp[u][i] += b[i - 1] ;
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int v = e[i] ;
        if(v == fa) continue ;
        dfs1(v , u) ;
    }
}
void dfs(int u , int fa)
{
    size[u] = 1 ;
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int v = e[i] ;
        if(v == fa) continue ;
        dfs(v , u) ;
        size[u] += size[v] ;
        dp[u][0] += dp[v][k - 1] + size[v] ;
        for(int i = 1; i < k ;i ++) dp[u][i] += dp[v][i - 1] ;
    }
    return ;
}
void work()
{
    cin >> n >> k ;
    memset(flow , 0 , sizeof flow) ;
    idx = 0 ;
    memset(h , -1 , sizeof h) ;
    for(int i = 1 , a , b , c ; i < n ;i ++)
        cin >> a >> b  ,
        add(a , b) , add(b , a);
    dfs(1, 0) ;
    dfs1(1 , 0) ;
    ll res = 0 ;
    for(int i = 1; i <= n ;i ++) res += 1ll * dp[i][0] ;
    cout << res / 2 << endl ;
    return ;
}
int main()
{
    work() ;
    return 0 ;
}

先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值