Leyni的国家II | ||||||
| ||||||
Description | ||||||
Leyni经过了若干年的征战,终于建立了自己的国家,这个国家包含n个城市,编号为1到n,而且这些城市中,任意两个城市间有且只有一种路线(这个路线可能需要经过若干条城市之间的公路),每条城市之间的公路的长度都相等(都是1单位长度)。 Leyni现在想知道有多少对城市之间的最短路径长度等于k。(城市u到城市v,城市v到城市u算一种) | ||||||
Input | ||||||
本题有多组测试数据,输入的第一行是一个整数T代表着测试数据的数量,接下来是T组测试数据。 对于每组测试数据: 第1行 包含两个以空格分隔的整数n和k (1 ≤ n ≤ 50000, 1 ≤ k ≤ 500)。 第2 .. n行 在这n – 1行中,每行包含两个以空格分隔的整数u和v (1 ≤ u, v ≤ n, u ≠ v),表示城市u和城市v之间存在一条双向公路。(数据保证所有给出的边都是不同的) | ||||||
Output | ||||||
对于每组测试数据: 第1行 输出有多少对城市之间的最短路径长度等于k。 | ||||||
Sample Input | ||||||
1 5 2 1 2 2 3 3 4 2 5 | ||||||
Sample Output | ||||||
4 | ||||||
Hint | ||||||
第一组样例的中最短路径长度等于2的路径有(1, 3) (1, 5) (3, 5) (2, 4)。 | ||||||
Author | ||||||
齐达拉图@HRBUST |
思路:
1、如果按照k作为深搜的深度,然后枚举n个点的深度为k的dfs,累加方案数,稳稳的TLE。pass。
2、题目说两个点之间的道路只有一条,那么就保证了图是连通的。那么图是一颗树,对于树上的dfs,不妨在树状dp方向多加于思考。
3、我们设定dp【i】【j】表示以i为根的子树中,距离i为j的点的个数。那么不难理解:
dp【i】【0】=1(1<=i<=n),dp【i】【j】+=dp【v】【j-1】;(1<=j<=k)
4、这样我们就得到了一个符合我们设定的数组dp【i】【j】。至于我们要得到的答案,在树状dp的同时,在更新dp【i】【j】之前,ans+=dp【i】【k-z-1】*dp【v】【z】(0<=z<k)//表示从v出发距离v为z的点的个数(从i出发距离为z+1)*从i出发距离i为k-z-1(从i出发距离为k-(z+1))的个数的累加
Ac代码:
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int >mp[50050];
int dp[50050][550];
int vis[50050];
int n,k,ans;
void DP(int u,int from)
{
vis[u]=1;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(vis[v]==0)DP(v,u);
if(v==from)continue;
for(int j=0;j<k;j++)
{
ans+=dp[v][j]*dp[u][k-j-1];
}
for(int j=1;j<=k;j++)
{
dp[u][j]+=dp[v][j-1];
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=0;i<n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
for(int i=1;i<=n;i++)dp[i][0]=1;
ans=0;
DP(1,-1);
printf("%d\n",ans);
}
}