【树形DP】 codeforces VK Cup 2012 Round 1 D

原题直通车: codeforces VK Cup 2012 Round 1 D

题意: 一颗树有n个结点,边长度都为1,问树中距离为K的点有多少对.

分析:

     对于某一结点A,到它距离为k的点有两种情况:

            1)、在以A为根结点的子树中;

            2)、在以兄弟结点为子结点的子树中(k>=2)如图(通过父结点与兄弟结点贯通)。


第一种用DFS可直接求出;

第二种:

       如对于结点i,其父结点为fa[i].

       假设i这个子树中距i等于j的点有x个,fa[i]子树中距fa[i]为k-j-1的结点有y 个,

       y个当中又在i子树中的有z个, 那么x与(y-z)这些结点的距离为k,数量为x*(y-z)对。

PS:求第二种时,可能会算出重复的(正好是两倍)。

比如:对于图中k=3时。

      ⑴ 、对于结点i=2,j=0则x=1,(y-z)=2(结点6和8)。

      ⑵ 、对于结点i=3, j=1则x=2,(y-z)=1(结点2)。

上面两种情况其实只能算一种。所以最终结果得除以2。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=55555;
vector<int>Tree[maxn];
int dp[maxn][555]; 
int pre[maxn];
int n,k;
void DFS(int cnt,int fa){
    pre[cnt]=fa;
    int len=Tree[cnt].size();
    for(int i=0;i<len;++i){
        int son=Tree[cnt][i];
        if(son==fa) continue;
        DFS(son,cnt);
    }
    dp[cnt][0]=1;
    if(fa)
        for(int i=0;i<k;++i)
            dp[fa][i+1]+=dp[cnt][i];
}
int main(){
    cin>>n>>k;
    for(int i=1;i<n;++i){
        int a,b; cin>>a>>b;
        Tree[a].push_back(b);
        Tree[b].push_back(a);
    }
    if(k==1){
        cout<<n-1<<endl; return 0;
    }
    DFS(1,0);
    long long ans=0;
    for(int i=1;i<=n;++i){
        if(!pre[i]) continue;
        ans+=(long long)dp[i][k-1]*2;
        for(int j=0;j<=k-2;++j)
            ans+=((long long)dp[i][j])*(dp[pre[i]][k-1-j]-dp[i][k-2-j]);
    }
    cout<<ans/2<<endl;
    return 0;
}

//



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值