参考博文:
<1>poj总结链接
<2> acwing 代码链接
<3> 数学证明
题目:
对于一颗n个结点的无根树,找到一条最长路径。(找到两个距离最远的点)
思路:
(树的重心问题)
先将无根树转换成有根树,即随意找一点i作为根节点,经过i的最长路就连接着两颗不同子树u和v的最深叶子节点的路径。
求解方法:
任意找一点i为根节点,找到距离该结点最远距离的点u。
再从u出发,寻找离u最远的节点v。u到v的距离即为树的最长路径。
动态规划三部曲
1)状态定义
dp[i] 表示以i为根节点的子树到叶节点的最大距离
2)状态转移方程
边权为1时:
dp[i] = max{dp[j] + 1}
边权不为1时:
dp[i] = max{dp[j] + w(i)}
(1)ACWing上的问题
类型:有边权
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 10010;
int n;
int ans;
struct Node {
int v, dis;
Node(int _v, int _dis) {
v = _v;
dis = _dis;
}
};
vector<Node> Adj[N];
int dfs(int u, int father) {
//根据贪心理论,以u为根的最长路径必然由经过不同的子树的最长和次长
int d1 = 0, d2 = 0;
for (int i = 0; i < Adj[u].size(); i++) {
int v = Adj[u][i].v;
int dis = Adj[u][i].dis;
if (v == father)
continue;
int d = dfs(v, u) + dis; //u->v之前的距离
//dist = max(dist, d);
if (d >= d1) {
d2 = d1;
d1 = d;
} else if (d > d2) {
d2 = d;
}
}
ans = max(ans, d1 + d2);
//cout << d1 << endl;
return d1;
}
int main() {
cin >> n;
int a, b, c;
for (int i = 0; i < n - 1; i++) {
cin >> a >> b >> c;
Adj[a].push_back(Node(b, c));
Adj[b].push_back(Node(a, c));
}
dfs(1, -1);
cout << ans << endl;
return 0;
}
(2) POJ上的问题
类型:有边权
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <vector>
using namespace std;
const int N = 10010;
int n, m;
struct Node {
int v, dis;
Node(int _v, int _dis) {
v = _v;
dis = _dis;
}
};
vector<Node> Adj[N];
int dis[N];
int vis[N];
void dfs(int u, int t) {
dis[u] = t;
for (int i = 0; i < Adj[u].size(); i++) {
int v = Adj[u][i].v;
if (vis[v] == false) {
vis[v] = true;
dfs(v, t + Adj[u][i].dis);
}
}
}
int main() {
int u, v, w;
int maxn = 0;
while (cin >> u >> v >> w) {
Adj[u].push_back(Node(v, w));
Adj[v].push_back(Node(u, w));
if (u > v) {
maxn = max(maxn, u);
} else {
maxn = max(v, maxn);
}
}
//cout << maxn << endl;
memset(dis, 0, sizeof dis);
fill(vis, vis + N, false);
dfs(1, 0);
int start = 0;
int maxdis = 0;
for (int i = 0; i <= maxn; i++) {
if (dis[i] > maxdis) {
start = i;
maxdis = dis[i];
}
}
memset(dis, 0, sizeof dis);
fill(vis, vis + N, false);
dfs(start, 0);
maxdis = 0;
for (int i = 0; i <= maxn; i++) {
if (dis[i] > maxdis) {
start = i;
maxdis = dis[i];
}
}
cout << maxdis << endl;
return 0;
}
(3) CCF-CSP上的问题
类型:无边权
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20010;
int dis[N]; // 用于存储最远距离
bool vis[N];
int n, m;
vector<int> Adj[N];
void dfs(int start, int t) {
dis[start] = t;
for (int i = 0; i < Adj[start].size(); i++) {
if (vis[Adj[start][i]] == false) {
vis[Adj[start][i]] = true;
dfs(Adj[start][i], t + 1);
}
}
}
int main() {
cin >> n >> m;
int a;
for (int i = 2; i <= n; i++) {
cin >> a;
Adj[i].push_back(a);
Adj[a].push_back(i);
}
for (int i = n + 1; i <= n + m; i++) {
cin >> a;
Adj[a].push_back(i);
Adj[i].push_back(a);
}
memset(dis, 0, sizeof dis);
fill(vis, vis + N, false);
int start = 0;
int maxdis = 0;
//寻找最远点u
dfs(1, 0);
for (int i = 1; i <= n + m; i++) {
if (dis[i] > maxdis) {
start = i;
maxdis = dis[i];
}
}
maxdis = 0;
memset(dis, 0, sizeof dis);
fill(vis, vis + N, false);
dfs(start, 0);
for (int i = 1; i <= n + m; i++) {
if (dis[i] > maxdis) {
maxdis = dis[i];
}
}
cout << maxdis << endl;
return 0;
}