Computer (求每个点的树上最远距离)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2196
思路:
我们定义f【i】表示编号为i的节点第一步向儿子方向走的最远距离
g【i】表示编号为i的节点第一步向父亲方向走的最远距离
p【i】表示编号为i的节点的父亲节点编号
w(a,b)表示编号a节点到编号b节点的距离,a和b是一条边连接的,即边权
用2个dfs求出这三个数组
递推式:f【u】=max(f【v】,w(u,v))//v是u的孩子
g【u】=w(u,p【u】)+max(g【p【u】】,f【v】+w(p【u】,u))//v是u的兄弟
两个递推式在下面讲解
对于第i个节点,答案就是max(f【i】,g【i】)
因为对一个节点来说,它的第一步只能是向孩子方向走(可能有多个孩子)或者向父亲方向走
往孩子方向走的转移方程很好列
往父亲方向走:
分情况: 1、父亲的父亲 -> 父亲 -> 当前节点
2、当前节点的兄弟 -> 父亲 -> 当前节点
#include <iostream> #include <algorithm> #include <string> #include <string.h> #include <vector> #include <map> #include <stack> #include <set> #include <queue> #include <math.h> #include <cstdio> #include <iomanip> #include <time.h> #include <bitset> #include <cmath> #define LL long long #define INF 0x3f3f3f3f #define ls nod<<1 #define rs (nod<<1)+1 const double eps = 1e-10; const int maxn = 1e4 + 10; const LL mod = 1e9 + 7; int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;} using namespace std; struct edge { int v,nxt,w; }e[maxn<<1]; int head[maxn]; int cnt; int f[maxn],g[maxn]; int p[maxn]; inline void add_edge(int u,int v,int w) { e[++cnt].v = v; e[cnt].w = w; e[cnt].nxt = head[u]; head[u] = cnt; } inline void dfs1(int x,int fa) { for (int i = head[x];~i;i = e[i].nxt) { int v = e[i].v; //int w = e[i].w; if (v == fa) continue; dfs1(v,x); p[v] = x; f[x] = max(f[x],f[v]+e[i].w); } } inline void dfs2(int x,int fa) { g[x] = g[fa]; int t = 0; for (int i = head[fa];~i;i = e[i].nxt) { int v = e[i].v; //int w = e[i].w; if (v == p[fa]) continue; if (v == x) t = e[i].w; else g[x] = max(g[x],f[v]+e[i].w); } g[x] += t; for (int i = head[x];~i;i = e[i].nxt) { int v = e[i].v; if (v == fa) continue; dfs2(v,x); } } int main() { int n; while (cin >> n) { memset(head,-1, sizeof(head)); memset(f,0, sizeof(f)); memset(g,0, sizeof(g)); memset(p,0, sizeof(p)); cnt = 0; for (int i = 2;i <= n;i++) { int u,v,val; cin >> v >> val; u = i; add_edge(u,v,val); add_edge(v,u,val); } dfs1(1,0); dfs2(1,0); for (int i = 1;i <= n;i++) cout << max(f[i],g[i]) << endl; } return 0; }