Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 38417 Accepted Submission(s): 6957
1 /************************************************************************* 2 > File Name: computer.cpp 3 > Author: CruelKing 4 > Mail: 2016586625@qq.com 5 > Created Time: 2019年09月23日 星期一 14时08分02秒 6 我的思路:先求出直径的两个端点,接着求出所有顶点到两个端点的距离,取其中最大的即是答案. 7 第二种思路:一个顶点距离其他顶点的最远距离要么经过儿子结点,要么经过父亲结点,那么我们就都求出来取其大就可以了. 8 需要注意的是,如果说一个说父亲的最远距离经过儿子的最远距离的话,儿子需要换一条路次短路. 9 ************************************************************************/ 10 11 #include <cstdio> 12 #include <cstring> 13 #include <algorithm> 14 using namespace std; 15 16 const int maxn = 10000 + 5; 17 struct Edge { 18 int to, cost, next; 19 } edge[maxn << 1]; 20 21 int n, ans; 22 23 int head[maxn], tot; 24 //int dp[maxn];//某棵树子树的大小 # TODO:这是用树的直径的时候保存的状态 25 26 int dp[maxn][3];//用dp[i][0]表示i的子树的最远距离,dp[i][1]表示i的子树的次远距离 27 //dp[i][2]表示i的祖先的最远距离,所以答案取max(dp[i][0], dp[i][2]) 28 29 void init() { 30 memset(head, -1, sizeof head); 31 tot = 0; 32 } 33 34 void addedge(int u, int v, int w) { 35 edge[tot].to = v; edge[tot].next = head[u]; edge[tot].cost = w; head[u] = tot ++; 36 edge[tot].to = u; edge[tot].next = head[v]; edge[tot].cost = w; head[v] = tot ++; 37 } 38 39 /* 40 void dfs(int u, int pre) { 41 //TODO:求解树的直径 42 //本题没用到该函数 43 for(int i = head[u]; ~i; i = edge[i].next) { 44 int v = edge[i].to; 45 if(v == pre) continue; 46 dfs(v, u); 47 if(ans < dp[u] + dp[v] + edge[i].cost) { 48 ans = dp[u] + dp[v] + edge[i].cost; 49 } 50 if(dp[v] + edge[i].cost > dp[u]) { 51 dp[u] = edge[i].cost + dp[v]; 52 } 53 } 54 } 55 */ 56 57 /* 58 int d, M; 59 int A, B; 60 61 int dist[maxn]; 62 63 void dfs(int u, int pre, bool flag) { 64 //TODO:递归寻找树的直径的端点 65 if(d > M) { 66 M = d; 67 if(flag) 68 A = u; 69 else 70 B = u; 71 } 72 for(int i = head[u]; ~i; i = edge[i].next) { 73 int v = edge[i].to; 74 if(pre == v) continue; 75 d += edge[i].cost; 76 if(!flag) dist[v] = d; 77 dfs(v, u, flag); 78 d -= edge[i].cost; 79 } 80 } 81 82 void dfs1(int u, int pre) { 83 //TODO;寻找每个点距离两个端点的最大值 84 for(int i = head[u]; ~i; i = edge[i].next) { 85 int v = edge[i].to; 86 if(pre == v) continue; 87 d += edge[i].cost; 88 dist[v] = max(d, dist[v]); 89 dfs1(v, u); 90 d -= edge[i].cost; 91 } 92 } 93 */ 94 95 void dfs(int u, int pre) { 96 for(int i = head[u]; ~i; i = edge[i].next) { 97 int v = edge[i].to; 98 if(v == pre) continue; 99 dfs(v, u); 100 int temp = 0; 101 if(dp[u][0] <= dp[v][0] + edge[i].cost) { 102 dp[u][1] = dp[u][0]; 103 dp[u][0] = dp[v][0] + edge[i].cost; 104 } else if(dp[u][1] < dp[v][0] + edge[i].cost) { 105 dp[u][1] = edge[i].cost + dp[v][0]; 106 } 107 } 108 // printf("%d %d %d\n", u, dp[u][0], dp[u][1]); 109 } 110 111 void dfs1(int u, int pre) { 112 for(int i = head[u]; ~i; i = edge[i].next) { 113 int v = edge[i].to; 114 if(v == pre) continue; 115 dp[v][2] = max(dp[u][2], dp[v][0] + edge[i].cost == dp[u][0] ? dp[u][1] : dp[u][0]) + edge[i].cost; 116 dfs1(v, u); 117 } 118 } 119 120 int main() { 121 int v, w; 122 while(~scanf("%d", &n)) { 123 ans = 0; 124 init(); 125 memset(dp, 0, sizeof dp); 126 for(int i = 2; i <= n; i ++) { 127 scanf("%d %d", &v, &w); 128 addedge(i, v, w); 129 } 130 /*TODO:利用树的直径求解本题 131 memset(dist, 0, sizeof dist); 132 d = M = 0; 133 dfs(1, -1, true); 134 M = 0; 135 dfs(A, -1, false); 136 // for(int i = 1; i <= n; i ++) { 137 // printf("%d\n", dist[i]); 138 // } 139 dfs1(B, -1); 140 for(int i = 1; i <= n; i ++) { 141 printf("%d\n", dist[i]); 142 } 143 */ 144 //TODO:利用树形dp求解本题 145 dfs(1, -1); 146 dfs1(1, -1); 147 for(int i = 1; i <= n; i ++) { 148 printf("%d\n", max(dp[i][0], dp[i][2])); 149 } 150 } 151 return 0; 152 }
原文:https://www.cnblogs.com/bianjunting/p/11577550.html