You are on page 1of 3

https://oj.vnoi.

info/problem/lqdxeui

Solution :
Trước hết, ta xét bài toán ở trường hợp dễ hơn là trọng số các đường đi bằng 1 v

Dễ thấy đường đi ngắn nhất chính là tổng các cạnh của cây hay chính là n – 1

Vậy nếu các đường chỉ được đi qua 1 lần thì sao?

Ở đây ta sẽ đưa ra cách đi như sau

Với mỗi đỉnh ta sẽ gọi mảng h[] là quãng đường di chuyển từ điểm bắt đầu đến đó

Ta sẽ gọi dfs 2 lần

+> Lần 1, ta sẽ cố gắng tìm được đỉnh có khoảng cách xa nhất so với gốc bắt đầu

ở đây là 5

+> Lần 2 ta sẽ gọi lại dfs từ đỉnh có khoảng cách lớn nhất đến các đỉnh còn lại vì khi đó ta sẽ có được
tổng các quãng đường đi cũng chính là giá trị h cao nhất sau khi gọi dfs

Quay lại bài toán gốc ban đầu

Hoàn toàn tương tự các bước trên, ta sẽ gọi dfs từ đỉnh bắt đầu của 2 xe và tính khoảng các và điểm xa
nhất so với gốc bắt đầu rồi sau đó lại dfs tiếp 1 lần nữa
Khi đó ta thu được tổng quãng đường dài nhất liên tiếp không đi qua 1 đường 2 lần

Ta sẽ gọi tổng các trọng số của cây là sum, nhận thấy rằng khi xe đi xuống cạnh dưới của cây thì nếu
muốn đi tiếp các cạnh khác của đỉnh ban đầu đang xét, ta cần phải leo lên lại về đường bắt đầu do đó sẽ
mất x2 trọng số để dọn xong đống đó nên nếu làm cách bình thường ta sẽ mất sum * 2

Tuy vậy, ta lại có 2 xe trên đường đi nên thực tế ta sẽ ưu tiên việc để những cạnh phải đi leo lên lại mà x2
là ít nhất do đó ta sẽ cho các cạnh có trọng số ít hơn lên x2 và các cạnh dài sẽ là 1 mà đường đi đó cũng
chính là quãng đường

Dfs lần 1, ta tìm ra được h[] max cần là 4 ta gọi dfs tiếp từ 4 sẽ tìm được quãng đường đi dài nhất mà ko
đi lại 1 đường là 4 - > 1 -> 2 do đó đáp án cần là sum * 2 – h[] max = (3 + 2 + 4) * 2 – (5 + 4) = 15

Code mẫu:
#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 5;

struct pii {

int fi, se;

};

vector<pii> adj[N];

int h[N];

pii maxi;

int visited[N];

void dfs(int i) {

visited[i] = true;

for (auto k : adj[i]) {

if (visited[k.fi]) {

continue;
}

h[k.fi] = h[i] + k.se;

maxi.fi = max(maxi.fi, h[k.fi]);

if (maxi.fi == h[k.fi]) {

maxi.se = k.fi;

//cout << k.fi << " " << k.se << " " << h[k.fi] << " " << i << '\n';

dfs(k.fi);

int main() {

int n, x;

cin >> n >> x;

int sum = 0;

maxi.fi = -1;

for (int i = 1; i <= n - 1; i ++) {

int u, v, t;

cin >> u >> v >> t;

adj[u].push_back({v, t});

adj[v].push_back({u, t});

sum += t;

dfs(x);

int tmpmax = maxi.se;

maxi.se = 0;

h[tmpmax] = 0;

memset(visited, 0, sizeof (visited));

dfs(tmpmax);

cout << sum * 2 - maxi.fi;

return 0;

You might also like