hdu 2196 树形dp

转自:http://blog.csdn.net/shuangde800

题目大意:

求树上所有点到树上另一点的最远距离;

基本思路:

把无根树转化成有根树分析,

对于上面那棵树,要求距结点2的最长距离,那么,就需要知道以2为顶点的子树(蓝色圈起的部分,我们叫它Tree(2)),距顶点2的最远距离L1

还有知道2的父节点1为根节点的树Tree(1)-Tree(2)部分(即红色圈起部分),距离结点1的最长距离+dist(1,2) = L2,那么最终距离结点2最远的距离就是max{L1,L2}

 

f[i][0],表示顶点为i的子树的,距顶点i的最长距离
f[i][1],表示Tree(i的父节点)-Tree(i)的最长距离+i跟i的父节点距离

 

要求所有的f[i][0]很简单,只要先做一次dfs求每个结点到叶子结点的最长距离即可。
然后要求f[i][1], 可以从父节点递推到子节点,

假设节点u有n个子节点,分别是v1,v2...vn
那么
如果vi不是u最长距离经过的节点,f[vi][1] = dist(vi,u)+max(f[u][0], f[u][1])
如果vi是u最长距离经过的节点,那么不能选择f[u][0],因为这保存的就是最长距离,要选择Tree(u)第二大距离secondDist,
可得f[vi][1] = dist(vi, u) + max(secondDist, f[u][1])

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

typedef long long ll;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const int maxn = 10000+10;

struct Node{
    int v,w;
};
vector<Node>adj[maxn];bool vis[maxn];
int n,m;
ll f[maxn][2];
//求f[u][0]
ll dfs1(int u){
    vis[u]=true;
    f[u][0]=0;
    int sz=adj[u].size();
    for(int i=0;i<sz;i++){
        int v=adj[u][i].v;
        int w=adj[u][i].w;
        if(vis[v]) continue;
        f[u][0]=max(f[u][0],dfs1(v)+w);
    }
    return f[u][0];
}
//求f[u][1]
void dfs2(int u,int fa_w){ vis[u]=true; int max1=0,v1,max2=0,v2; int sz=adj[u].size(); for(int i=0;i<sz;++i){ int v=adj[u][i].v; int w=adj[u][i].w; if(vis[v]) continue; int tmp=f[v][0]+w; if(tmp>max1){ max2=max1;v2=v1; max1=tmp;v1=v; }else if(tmp==max1||tmp>max2){ max2=tmp; v2=v; } } if(u!=1){ int tmp=f[u][1]; int v=-1; if(tmp>max1){ max2=max1;v2=v1; max1=tmp;v1=v; }else if(tmp==max1||tmp>max2){ max2=tmp; v2=v; } } for(int i=0;i<sz;i++){ int v=adj[u][i].v; int w=adj[u][i].w; if(vis[v]){ continue; } if(v==v1){ f[v][1]=max2+w; }else{ f[v][1]=max1+w; }//如果v==v1,说明v1在u的最长距离上,那么v的最长距离就不能用max1,只能用max2; dfs2(v,w); } } int main(){ while(~scanf("%d",&n)&&n){ for(int i=1;i<=n;i++){ adj[i].clear(); } for(int u=2;u<=n;u++){ int v,w; scanf("%d%d",&v,&w); adj[u].push_back((Node){v,w}); adj[v].push_back((Node){u,w}); } memset(f,0,sizeof(f)); memset(vis,0,sizeof(vis)); dfs1(1); memset(vis,0,sizeof(vis)); dfs2(1,0); for(int i=1;i<=n;i++){ printf("%lld\n",max(f[i][0],f[i][1])); } } return 0; }

 

posted @ 2018-01-31 15:03  愿~得偿所愿,不负时光  阅读(136)  评论(0编辑  收藏  举报