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

来源:互联网 发布:ios 矩阵运算 编辑:程序博客网 时间:2024/04/28 04:34

原题直通车: 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;}//