樹的直徑&&樹形dp
阿新 • • 發佈:2020-09-07
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(); }