打多校才发现连树的直径都忘了,赶紧来复习一下树的直径
这里只讲裸的树的直径..
有两种常见的方法去求树的直径
树形dp写法:
第一种是树形dp,我们随便选个结点作为根将有根树转化为无根树,用dp[x]表示以x为根的子树中从x出发的最长链的长度,如果Yi是x的儿子们,那么状态转移是这样的dp[x]=max(dp[x],dp[y]+Edge),接下来考虑经过x的最长链的长度f[x],那么max(f[i],1<=i<=n)就是树的直径了,假设yi,yj是x的两个直接相连的结点,那么f(x)=max(dp[yi]+dp[yj]+x与yi,yj的距离)
具体实现就在下面了
#include <bits/stdc++.h>
using namespace std;
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i < n; i++)
#define per(i, a, n) for (int i = n - 1; i >= a; i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef vector<int, int> VII;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e3 + 7;
const ll MAXM = 1e5 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
int n, m;
struct Edge
{
int from, to, val;
int next;
} E[MAXM];
int cnt = -1;
int ans = -inf;
int head[MAXN];
int dp[MAXN]; /* dp[x]表示从结点x出发,往以x作为根的子树走,能够到达的最远距离 */
void add(int from, int to, int val)
{
E[++cnt].from = from;
E[cnt].to = to;
E[cnt].val = val;
E[cnt].next = head[from];
head[from] = cnt;
}
void init()
{
ans = -inf;
cnt = -1;
memset(head, -1, sizeof(head));
memset(dp, 0, sizeof(dp));
}
/* 求树的直径 */
void tree_dp(int u, int fa) /* 随便选个结点作为根结点把树转换成有根树 */
{
for (int i = head[u]; i != -1; i = E[i].next)
{
int to = E[i].to;
if (fa == to)
continue;
tree_dp(to, u);
ans = max(ans, dp[u] + dp[to] + E[i].val);
dp[u] = max(dp[u], dp[to] + E[i].val);
}
}
int main()
{
init();
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int u, v, val;
cin >> u >> v >> val;
add(u, v, val); //建边
add(v, u, val);
}
tree_dp(1, -1);
cout << ans << endl;
return 0;
}
两次dfs或者bfs:
这样写还方便计算出直径上的具体结点。
第一次dfs从任意结点出发对树进行遍历,求出与出发点距离最远的结点记为x
那么从x出发,通过第二次dfs在进行一次遍历,求出与x距离最远的结点y,该结点与结点x得路径长度就是树的直径,这个方法是显然正确的,x肯定是直径的一端,y就是另一端,相连就是树的直径
bfs也差不多...但是不是很想写...
两次dfs具体实现
#include <bits/stdc++.h>
using namespace std;
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i < n; i++)
#define per(i, a, n) for (int i = n - 1; i >= a; i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef vector<int, int> VII;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e3 + 7;
const ll MAXM = 1e5 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
int n, m;
struct Edge
{
int from, to, val;
int next;
} E[MAXM];
int cnt = -1;
int ans = -inf;
int head[MAXN];
int vis[MAXN];
int dis[MAXN];
void add(int from, int to, int val)
{
E[++cnt].from = from;
E[cnt].to = to;
E[cnt].val = val;
E[cnt].next = head[from];
head[from] = cnt;
}
void init()
{
ans = -inf;
cnt = -1;
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(dis, 0, sizeof(dis));
}
/* 求树的直径 */
void dfs(int u)
{
vis[u] = 1;
for (int i = head[u]; i != -1; i = E[i].next)
{
int to = E[i].to;
if (vis[to])
continue;
dis[to] = dis[u] + E[i].val;
dfs(to);
}
return;
}
int main()
{
init();
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int u, v, val;
cin >> u >> v >> val;
add(u, v, val); //建边
add(v, u, val);
}
dfs(1); /* 第一遍dfs */
int maxx = -inf, start = -1;
for (int i = 1; i <= n; i++)
{
if (dis[i] > maxx)
{
maxx = dis[i];
start = i;
}
dis[i] = vis[i] = 0;
}
dfs(start); /* 第二遍dfs */
for (int i = 1; i <= n; i++)
ans = max(dis[i], ans);
cout << ans << endl;
return 0;
}
/* 7 6
1 2 1
1 3 4
2 4 2
2 5 3
3 6 5
3 7 6 */