codeforces 161D D. Distance in Tree(树形dp)

来源:互联网 发布:极右势力的网络保护伞 编辑:程序博客网 时间:2024/04/29 14:56

题目链接:

codeforces 161D


题目大意:

给出一棵树,每条边的边权是1,问两点之间的路径长度为k的点对有多少个?


题目分析:

  • 定义状态dp[i][k]代表以i为根的子树中的点到达点i的长度为k的点的个数。定义V为与u相邻的点的集合,p是u的父亲
  • 然后转移方程很简单:
    dp[u][j]=vVdp[v][j1]
  • 然后我们利用处理出来的dp数组可以再做一个操作,将它变成点i到所有点中路径长度等于k的个数。
  • 转移方程如下:
    dp[u][j]+=dp[p][j1]dp[u][j2]
  • 就是因为父亲已经被维护过,所以现在dp[p][j-1]表示p点到所有点中长度为k的点的个数,再减去那些存在于当前子树中的点,然后就是非u的子树中的点到u的距离为j的点的个数,最后枚举每个点,统计他们ni=1dp[u][k],因为每条符合要求的路径算了两次,所以最后结果要除以2。

AC代码:

#include <iostream>#include <cstring>#include <cstdio>#include <vector>#include <algorithm>#define MAX 50007using namespace std;typedef long long LL;int n,k,a,b;LL dp[MAX][507],ans;vector<int> e[MAX];void add ( int u , int v ){    e[u].push_back ( v );    e[v].push_back ( u );}void Clear ( ){    for ( int i = 0 ; i < MAX ; i++ )        e[i].clear();}void dfs ( int u , int p ){    dp[u][0] = 1;    for ( int i = 1 ; i <= k ; i++ )        dp[u][i] = 0;    for ( int i = 0 ; i < e[u].size() ; i++ )    {        int v = e[u][i];        if ( v == p ) continue;        dfs ( v , u );        for ( int j = 1 ; j <= k ; j++ )            dp[u][j] += dp[v][j-1];    }}void solve ( int u , int p ){    for ( int i = 0 ; i < e[u].size() ; i++ )    {        int v = e[u][i];        if ( v == p ) continue;        for ( int j = k; j >= 1 ; j-- )        {            dp[v][j] += dp[u][j-1];            if ( j > 1 ) dp[v][j] -= dp[v][j-2];        }        solve ( v , u );    }}int main ( ){    while ( ~scanf ( "%d%d" , &n , &k ) )    {        Clear();        for ( int i = 1 ; i < n ; i++ )        {            scanf ( "%d%d" , &a , &b );            add ( a , b );        }        ans = 0;        dfs ( 1 , -1 );        solve ( 1 , -1 );        /*for ( int i = 1; i <= n ; i++ )            for ( int j = 0 ; j <= k ; j++ )                cout << i << " " << j << " " << dp[i][j] << endl;*/        for ( int i = 1 ; i <= n ; i++ )            ans += dp[i][k];        printf ( "%I64d\n" , ans/2LL );    }}
0 0
原创粉丝点击