HDU2196 computer(树上最远距离 + DP)

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;
}

猜你喜欢

转载自blog.csdn.net/qq_40642465/article/details/81133778