C 小A与欧拉路 牛客练习赛40 树的直径

题解

首先考虑欧拉回路的情况,由于所给的图是一棵树则如果想构成欧拉回路就需要将每条边都复制一份
但是题目没要求回到出发点,则可以只从一个点出发到另一个点结束,所走路径也就是少了从出发点到终止点的路径
这个路径可以自己选择,则选择所给树形图中权值长度最大的两个点收益最大,也就是树的直径
树的直径使用两次DFS可以得到。

AC代码

#include 
#include 
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 4e5 + 10;
int h[MAXN], idx;

struct edge
{
	int v, w, nxt;
}e[MAXN];
void AddEdge(int u, int v, int w)
{
	e[++idx] = { v, w, h[u] }; //前++编号从1到n 循环判断非0即可不用初始化-1
	h[u] = idx;
}
pair<int, ll> DFS(int x, int f)
{
	ll mx = 0;
	int k = x;
	for (int i = h[x]; i; i = e[i].nxt)
	{
		int y = e[i].v;
		if (y != f)
		{
			pair<int, ll> res = DFS(y, x);
			if (res.sed + e[i].w > mx)
				mx = res.sed + e[i].w, k = res.fst;
		}
	}
	return{ k, mx };
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int n;
	cin >> n;
	ll s = 0;
	for (int i = 1; i < n; i++)
	{
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		AddEdge(u, v, w);
		AddEdge(v, u, w);
		s += w * 2;
	}
	pair<int, ll> res = DFS(1, 0);
	res = DFS(res.fst, 0); //两次DFS求树的直径
	cout << s - res.sed << endl; //边权和2倍-树的直径

	return 0;
}

你可能感兴趣的:(___图论___,树的直径)