http://acm.hdu.edu.cn/showproblem.php?pid=2196
引用下别人的:
题意:给定一棵树,求每一个节点所能到达的最长路径的长度
分析:以编号的i的节点为例(非根节点),最长的路径长度只有俩种可能,1)子树中存在最长路径;2)通过父节点的路径中存在最长路径
所以,只有分别求出每一节点对应的那俩种路径取大最大值即可,当然,根节点只存在第一种可能
上面也给出了思路,有个要注意的地方是:
通过父亲结点找的最长路径不能经过这个结点本身。
这就要求父节点保存两个最值(最大和次大)
Realize:
先建图,这里用邻接表存储较好。
DP:
f[i]代表的是向下的最长路径
g[i]向下的次长路径
h[i]向上的最长路径
分两次DP
f[i]/g[i] = max{ f[child] } + w;
h[i] = max{h[parent], f[parent]/g[parent]} + w;
顺便学习了下STL里的vector的用法,有了STL,生活变得更简单~~~~
#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
using namespace std;
#define MAX(a,b) ((a)>(b)?(a):(b))
struct edge
{
int ev,w;
edge(){}
edge(int a,int b):ev(a),w(b){}
};
vector <edge> elist[10009];
int g[10009],f[10009],h[10009];
void DFS1(int fv)
{
int size = elist[fv].size();
if (!size)
{
f[fv] = g[fv] = 0;
return;
}
int ev,w;
for (int i = 0;i < size;i++)
{
ev = elist[fv][i].ev;
w = elist[fv][i].w;
DFS1(ev);
if (f[ev] + w >= f[fv])
{
g[fv] = f[fv];
f[fv] = f[ev] + w; //?
}
else
{
if (f[ev] + w > g[fv])
g[fv] = f[ev] + w;
}
}
}
void DFS2(int fv)
{
int size = elist[fv].size();
if (!size)
{
return;
}
int ev,w;
for (int i = 0;i < size;i++)
{
ev = elist[fv][i].ev;
w = elist[fv][i].w;
if (f[ev] + w != f[fv])
{
h[ev] = MAX(h[fv],f[fv]) + w;//h[i] = MAX(h[fv],f[fv]) + w;
}
else
{
h[ev] = MAX(h[fv],g[fv]) + w;
}
DFS2(ev);
}
}
int main()
{
freopen("test.txt","r",stdin);
int N;
while(~scanf("%d",&N))
{
for (int i = 1;i <= N;i++)
elist[i].clear();
int fv,w;
for (int i = 2;i <= N;i++)
{
scanf("%d%d",&fv,&w);
elist[fv].push_back(edge(i,w));
}
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
DFS1(1);
DFS2(1);
for (int i = 1;i <= N;i++)
{
//cout<<f[i]<<" "<<h[i]<<endl;
printf("%d\n",MAX(f[i],h[i]));
}
}
return 0;
}