Roads in the North POJ - 2631 树的直径 BFS | 树形dp

题解

题目大意 给你n-1条带权边组成一个n个节点的树 题目没给n接收到文件尾 求这个树的直径 树的直径为树中两个距离最远点的距离

方法1 两次BFS
第一次任找一点为起点进行BFS得到最远的点p 点p一定为直径上的一个端点
第二次以p为起点再次BFS得到最远的点q 并求出pq之间的距离即为树的直径

AC代码

#include <stdio.h>
#include <iostream>
#include <vector>
#include <queue>
#include <string.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e4 + 10;

struct node
{
	int v, w;
	node(int a = 0, int b = 0) : v(a), w(b) {}
};
vector<node> e[MAXN];
int vis[MAXN];

node BFS(int x) //返回最远节点和最远距离
{
	node res; //结果
	queue<node> q;
	q.push(node(x, 0));
	vis[x] = 1;
	while (!q.empty())
	{
		int u = q.front().v, c = q.front().w;
		q.pop();
		for (int i = 0; i < e[u].size(); i++)
		{
			int v = e[u][i].v, w = e[u][i].w;
			if (!vis[v])
			{
				vis[v] = 1;
				q.push(node(v, c + w));
				if (res.w < c + w) //更新结果
					res = node(v, c + w);
			}
		}
	}
	return res;
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int u, v, w;
	while (scanf("%d%d%d", &u, &v, &w) != EOF)
		e[u].push_back(node(v, w)), e[v].push_back(node(u, w));
	int p = BFS(1).v; //随意选取一点找到最远点p
	memset(vis, 0, sizeof(vis));
	cout << BFS(p).w << endl; //再从p找到最远点q则pq为树的直径

	return 0;
}

方法2 树形dp
d[i]表示从i到叶子节点的最长路径 p[i]表示经过i的最长路径
d[i]在DFS回溯后通过叶子节点转移 即d[i] = max(d[i], d[j] + i到j距离)
p[i]为两个子节点到叶子节点的距离+到两个子节点的距离 如果使用双重循环jk会导致超时 在更新d[i]之前更新p[i]
p[i] = max(p[i], d[i] + d[k] + i到k距离) d[i]表示着到k以前的子节点的叶子最大距离再加上d[k]和到k的距离

AC代码

#include <stdio.h>
#include <iostream>
#include <vector>
#include <queue>
#include <string.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e4 + 10;
int d[MAXN], p[MAXN]; //d[i]从i到叶子节点的最长路径 p[i]经过i的最长路径
int ans;

struct node
{
	int v, w;
	node(int a = 0, int b = 0) : v(a), w(b) {}
};
vector<node> e[MAXN];

void DFS(int x, int f)
{
	for (int i = 0; i < e[x].size(); i++)
	{
		int y = e[x][i].v, z = e[x][i].w;
		if (y != f)
		{
			DFS(y, x);
			//最长路径等于两个子节点到叶子节点的距离+到两个子节点的距离 这里不使用双重循环求最大值
			p[x] = max(p[x], d[x] + d[y] + z); //d[x]表示着i-1的最优答案和选择i子节点的长度和
			d[x] = max(d[x], d[y] + z); //子节点+到子节点长度
		}
	}
	ans = max(ans, p[x]);
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int u, v, w;
	while (scanf("%d%d%d", &u, &v, &w) != EOF)
		e[u].push_back(node(v, w)), e[v].push_back(node(u, w));
	DFS(1, 0); //任取一点作为根
	cout << ans << endl;

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值