C-小A與歐拉路
題意:求圖中最短的歐拉路。
題解:因爲是一棵樹,因此當從某一個節點遍歷其子樹的時候,如果還沒有遍歷完整個樹,一定還需要再回到這個節點再去遍歷其它子樹,因此除了從起點到終點之間的路,其它路都被走了兩次,而我們要求總的路程最短,那麼我們就讓從起點到終點的路最長即可,也就是樹的直徑。所以答案就是所有邊權的兩倍再減去樹的直徑。
代碼
- 兩次dfs
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
#define P pair<int,LL>
typedef long long LL;
using namespace std;
const int N = 2E5+10;
LL d[N];
vector<P> E[N];
void dfs(int u,int fa)
{
for(auto &it : E[u]) {
int v = it.first;
LL w = it.second;
if(fa == v) continue;
d[v] = d[u] + w;
dfs(v,u);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int n, u, v, w;
LL sum = 0;
cin >> n;
for(int i = 0; i < n - 1; ++i) {
cin >> u >> v >> w;
E[u].push_back(P(v,w));
E[v].push_back(P(u,w));
sum += 2 * w;
}
dfs(1,0);
int rt = 1;
for(int i = 1; i <= n; ++i) {
if(d[rt] < d[i]) rt = i;
DEBUG(d[i]);
}
d[rt] = 0;
dfs(rt,0);
cout << sum - *max_element(d + 1,d + n + 1) << endl;
return 0;
}
- 樹形dp
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
#define P pair<int,int>
using namespace std;
const int N = 2E5+10;
typedef long long LL;
LL dp[N][2], maxL;
vector<P> E[N];
void dfs(int u,int fa)
{
for(auto &it : E[u]) {
int v = it.first;
int w = it.second;
if(fa == v) continue;
dfs(v,u);
if(dp[v][0] + w > dp[u][0]) { //如果以u爲根節點的最長鏈可以被它的兒子v更新
dp[u][1] = dp[u][0]; //那麼此時以u爲根節點的次長鏈變爲dp[u][0];
dp[u][0] = dp[v][0] + w; //最長鏈被更新
}else if(dp[v][0] + w > dp[u][1]) { //如果不能更新最長鏈但是卻可以更新次長鏈
dp[u][1] = dp[v][0] + w;
}
}
maxL = max(maxL,dp[u][1] + dp[u][0]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int n,u,v,w;
LL sum = 0;
cin >> n;
for(int i = 0; i < n - 1; ++i) {
cin >> u >> v >> w;
E[u].push_back(P(v,w));
E[v].push_back(P(u,w));
sum += 2 * w;
}
dfs(1,0);
cout << sum - maxL << endl;
return 0;
}