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