您的位置:首页 > 其它

codeforces 161D Distance in Tree (树形DP 经典题)

2015-08-31 15:57 211 查看
题意:给你一颗树,和一个数k,问树中长度为k的路径的条数.

分析:一看就是树形DP的类型.树形DP的特点就是用所有叶子节点的信息更新出其父亲节点,然后这些父亲节点再作为叶子节点,这样层层递归直到根节点.

这里很容易想到的一种叶子节点更新父亲节点的方式如下:

定义dp[i][j]dp[i][j]为节点i为根的所有子树中长度为j的路径的条数.

那么就容易有:dp[i][j]=∑u(u为i的所有子节点)dp[u][j−1]dp[i][j] = \sum_{u(u为i的所有子节点)}dp[u][j - 1]

这样层层的递归调用就可以从子节点更新到根节点了.

但是样根据树的乘法原理算出路径数,还需要一边更新,一边计算.计算的原则是每往该节点加入一个分支,就用该分支和前面已经加入的分支总和来进行组合相乘.

Code:

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int M = int(1e5 + 1), INF = 0x3fffffff, mod = 1000000007;
int dp[50009][509], n, k;
long long ans = 0;
vector<int> v[50009];

void dfs(int p, int prev)
{
    int u;
    dp[p][0] = 1;
    for (int i = 0; i < v[p].size(); i++) {
        u = v[p][i];
        if (u == prev) continue;  //只计算当前节点的只树的距离,根节点跳过
        dfs(u, p);
        for (int i = 0; i < k; i++)
            ans += dp[p][i] * dp[u][k - i -1];   //把当前节点要加入的分支,并组合相乘更新答案
        for (int i=0; i<k; i++)
            dp[p][i + 1] += dp[u][i];   //由子树来更新当前节点
    }
    return;
}

int main(void)
{
    cin >> n >> k;
    for (int i = 0; i < n - 1; i++) {
        int x, y;
        cin >> x >> y;
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs(n, -1);
    cout << ans  << endl;
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: