树的直径是指树上的最长链(如果是要节点最多的链那就边权作为1处理)
如下图所示,我们发现,对于每个节点(叶子除外)如果它是最长链上的点,那么最长链等于以这个节点为根时的最长的两条子链之和。因此,对于求最长链,我们可以转化成求树中的每个节点的最长的两个子链之和的问题;
这样一来,对于每个节点情况就有3种 :
1. 最长链恰好就是他的两条最长子链之和
2. 最长链是他的最长子链和其与父亲相连的那条链的 最大值之和
3. 这个点不在最长链上
因此我们可以做一次DFS+DP
实际上如果这个节点是非根节点时,他通往父节点的那条链在DFS时并未算作他的子链,但是,换个角度,他可以是他父节点的子链,这样以来情况2的情况也是满足的。
于是 我们需要保存的节点信息是这个节点最长的两个子链长度,没有就是0
接着 比较当前的最长链的值 与 此次两条子链的大小之和 判断是否更新当前最长链的值
DFS结束后的就是答案;
另外 还有另一种求最长链的方式
随意从一个点出发BFS找离这个点最远的那个点,下一次从找到的那个点再做一次BFS找最远点,而第二次的路径长度就是最长链的值。
关于这个问题,我们只要证明第一次BFS出来的那个点N是最长链上的起点(或者终点);
因为BFS1求的是最长链,所以最后找到的那个点一定是一片叶子,也就是某条链的起点(或者终点);
因此
(假设1)我们只要证明在第一次BFS的时候能够通过最长链上的点P则就能证明第一次BFS出来的那个点是最长链的起点(或者终点);(因为假设通过点P而N不是最长链上的点,那么P到N点的值将会大于他到已知最长链上的某个末尾的值,那么这条链就和已知最长链矛盾,所以假设1是成立的)
假设2 树上的任意一个点做BFS1的时候都会至少经过一个最长路上的点;
如图,我们假设已知的最长链(蓝色的点)的长度 LENMAX=F+K;起始点为红色S,以及绿色的不是最长链上的点Q;K为P->N之间的长度(以此类推其他边上的字母)
那么假设某个点做BFS1时不经过P点,由BFS的优先关系作为参考,可以得出
M+R>M+X+K =>R>X+K => F+X+R>(F+K)+2X=LENMAX+2X 与已知条件矛盾 ,假设2成立.
例子是poj 1985 Cow Marathon
题目的意思就是一棵树的最长链
思路差不多就是上面那样
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#define pi acos(-1.0)
#define inf 1<<29
#define INF 0x3f3f3f3f
#define zero 1e-8
const int li[] = { -1, 0, 1, 0};
const int lj[] = {0, -1, 0, 1};
using namespace std;
const int N = 4e4 + 7;
int maxlen;//最长链的长度
bool flag[N];
struct Node {
int max1, max2; //子链中最长的两条链
} tree[N];
vector<int> edge[N];
vector<int> lens[N];
void init(int n)
{
maxlen = 0;
memset(flag, false, sizeof(flag));
for (int i = 0; i <= n; ++i) {
edge[i].clear();
lens[i].clear();
tree[i].max1 = tree[i].max2 = 0;
}
}
void dfs(int node)
{
int max1 = 0, max2 = 0;
int tag = 0;
for (int i = 0; i < edge[node].size(); ++i) {
if (flag[edge[node][i]]) continue;
tag++;
flag[edge[node][i]] = true;
dfs(edge[node][i]);
int childlen = tree[edge[node][i]].max1 + lens[node][i];
if (max1 < max2) {
if (max1 < childlen) max1 = childlen;
} else if (max2 < childlen) {
max2 = childlen;
}
}
int maxx = max1 > max2 ? max1 : max2;
int minn = max1 > max2 ? max2 : max1;
if (!tag) {
tree[node].max1 = tree[node].max2 = 0;
} else if (tag == 1) tree[node].max1 = maxx, tree[node].max2 = 0;
else {
tree[node].max1 = maxx ;
tree[node].max2 = minn ;
}
maxlen = maxlen > (tree[node].max1 + tree[node].max2) ?
maxlen : (tree[node].max1 + tree[node].max2);
}
int main()
{
int n, m;
while(~scanf("%d %d", &n, &m)) {
init(n);
int l, r, len;
int id;
for (int i = 0; i < m; ++i) {
char c;
scanf("%d %d %d %c", &l, &r, &len, &c);
edge[l].push_back(r);
edge[r].push_back(l);
lens[l].push_back(len);
lens[r].push_back(len);
}
flag[1] = true;
dfs(1);
printf("%d\n", maxlen);
}
return 0;
}