http://acm.hdu.edu.cn/showproblem.php?pid=2196
题目大意就是给你n个点,还有这n个点的连接关系,然后分别输出这n个点到其他点的最长距离是多少?
这就是个树上最长距离,这题有2种解法,我用的是记忆化搜索,树形dp有时间再补了。如果是对每一个点都当作树的根节点,来一个dfs求最长路的话就太暴力了,会超时,所以就用到了记忆化搜索,每一个搜索的结果到保存在了dp数组里,那么就能避免一些重复的搜索了。这里用的是前向星存的边,然后有条边存在e[i]这个边结构体里,那么dp[i]表示的就是走这条边(走这条边指的是从这条边的起点u往v方向走)能够获得的最长距离.1.当搜索到root点时,向root点的相邻点v进行进一步搜索,当然前提是不是root的父节点,往v节点搜索是为了获取v节点能往下走的最长距离,从而获得root节点往v节点方向走的最长距离,但是如果root节点往v节点方向走的最长距离即dp[i]在之前的搜索就已经知道了的话,就不必往v节点搜索,直接更新ans. 2但是如果root节点往v节点方向走的最长距离即dp[i]在还不知道的话,就要搜下去了,然后返回一个v节点能往下走的最长距离,dp[i]=v节点能往下走的最长距离+e[i].w,这样就更新了这个dp[i],下次还要往v节点搜索时就不必搜索了。
#include<iostream>//记忆化搜索,前向星
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 10005
struct edge
{
int v,w,nx;
edge(){;}
edge(int vv,int ww,int nxx){v=vv;w=ww;nx=nxx;}
}e[2*maxn];
int head[maxn];
int dp[2*maxn];//dp[i]表示的是经过第i条边所能走的最长距离,要求是从该边的u往v方向走
int n,ecnt;
int dfs(int root,int p)
{
int ans=0;
for(int eindex=head[root];eindex!=-1;eindex=e[eindex].nx)
{
int v=e[eindex].v,w=e[eindex].w;
if(v==p) continue;
if(!dp[eindex]) dp[eindex]=dfs(v,root)+w;
ans=max(ans,dp[eindex]);
}
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
ecnt=0;
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
for(int u=2;u<=n;u++)
{
int v,w;
cin>>v>>w;
e[ecnt]=edge(v,w,head[u]);
head[u]=ecnt;
ecnt++;
e[ecnt]=edge(u,w,head[v]);
head[v]=ecnt;
ecnt++;
}
for(int i=1;i<=n;i++)
{
cout<<dfs(i,-1)<<endl;
}
}
return 0;
}