树的直径&&树形dp

http://acm.hdu.edu.cn/status.php
题意:给出一棵树,求出所有结点所能到达的最远距离。
解法一:任意一点所能到达的最远距离一定是树的直径的某一端点;由树的直径的性质可得。

#include<bits/stdc++.h>

using namespace std ;
typedef long long ll ;
const int N = 10010 , M = 20010 ;
int e[M] , w[M] , ne[M] , h[N] , idx ;
int n ;
int p , len , d[N];//d[i]表示i结点所能到达的最远距离

void add(int a , int b , int c){
    e[idx] = b , w[idx] = c , ne[idx] = h[a] , h[a] = idx++;
}

void dfs(int u , int pre, int dep){
    d[u] = max(d[u] , dep);
    if(dep > len){
        len = dep ;
        p = u ;
    }
    for(int i = h[u] ; ~i  ; i = ne[i]){
        int j = e[i];
        if(j == pre) continue;
        dfs(j , u ,  dep + w[i]);
    }
}
void solve(){
    memset(h , -1 , sizeof(h));
    memset(d , 0 , sizeof(d));
    p = 1 , len = 0 , idx = 0 ;
    for(int i = 2 ; i <= n ; i++){
        int a , b ;
        cin >> a >> b ;
        add(i , a , b);
        add(a , i , b);
    }
    dfs(p , 0 , 0);
    len = 0 ;
    dfs(p , 0 , 0);//直径一段
    dfs(p , 0 , 0);//直径另一端
    for(int i = 1 ; i <= n ; i++){
        cout << d[i] << endl;
    }
}

int main(){
    #ifdef ONLINE_JUDGE
	#else
		freopen("D:\\c++\\in.txt", "r", stdin);
		//freopen("D:\\c++\\out.txt", "w", stdout);
	#endif
    while(cin >> n)
        solve();
}

解法二:树形dp

#include<bits/stdc++.h>

using namespace std ;
typedef long long ll ;
const int N = 10010 , M = 20010 ;
int f[N][3];//f[i][0]表示以i为子树的离i最远距离,f[i][1]表示以i为子树且与最远距离所经过的儿子不同的离i最远距离,表示f[i][2]表示i的父节点去除i子树的最远距离
int e[M] , w[M] , ne[M] , h[N] , idx ;
int n ;
int maxson[N];
void add(int a , int b , int c){
    e[idx] = b , w[idx] = c , ne[idx] = h[a] , h[a] = idx++;
}

void dfs1(int u , int pre){//处理出f[i][0] , f[i][1]
    f[u][0] = f[u][1] = 0 ;
    for(int i = h[u] ; ~i  ; i = ne[i]){
        int j = e[i];
        if(j == pre) continue;
        dfs1(j , u);
        if(f[j][0] + w[i] >= f[u][0]){
            maxson[u] = j ;
            f[u][1] = f[u][0] , f[u][0] = f[j][0] + w[i] ;
        }else if(f[j][0] + w[i] > f[u][1]){
            f[u][1] = f[j][0] + w[i] ;
        }
    }
}

void dfs2(int u , int pre){//通过父节点更新儿子的f[v][2]表示v的父节点除去v子树的最远距离
    for(int i = h[u] ; ~i ; i = ne[i]){
        int j = e[i] ;
        if(j == pre) continue ;
        if(maxson[u] != j){
            f[j][2] = max(f[u][2] , f[u][0]) + w[i] ;
        }else{
            f[j][2] = max(f[u][2] , f[u][1]) + w[i] ;
        }
        dfs2(j , u);
    }
}

void solve(){
    memset(h , -1 , sizeof(h));
    idx = 0 ;
    for(int i = 2 ; i <= n ; i++){
        int a , b ;
        cin >> a >> b ;
        add(i , a , b);
        add(a , i , b);
    }
    dfs1(1 , 0);
    dfs2(1 , 0);
    for(int i = 1 ; i <= n ; i++){
        cout << max(f[i][0] , f[i][2]) << endl;
    }
}

int main(){
    #ifdef ONLINE_JUDGE
	#else
		freopen("D:\\c++\\in.txt", "r", stdin);
		//freopen("D:\\c++\\out.txt", "w", stdout);
	#endif
    while(cin >> n)
        solve();
}
posted @ 2020-09-06 20:07  无名菜鸟1  阅读(180)  评论(0编辑  收藏  举报