1207. 大臣的旅费-树的直径-树型dp+dfs++多看几遍啊
1207. 大臣的旅费树的直径 = 所有点的最长链+次长链的最大值优质题解树型dp某个点的最长链 = 连接该点和其子节点的边 + 子节点的最大值。很像dfs。#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int N = 2e5+10;struct e
·
1207. 大臣的旅费
树的直径 = 所有点的最长链+次长链的最大值
优质题解
树型dp
某个点的最长链 = 连接该点和其子节点的边 + 子节点的最大值。
很像dfs。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2e5+10;
struct edge{
int v,next,w;
}e[N];
int cnt = 0;
int n,ans = 0;
int head[N];
void add(int u,int v,int w)
{
e[cnt].v = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt++;
}
//树的直径 = 所有边里的最长边 + 次长边
int dfs(int u,int father) //返回到u的最长的边
{
int d1 = 0,d2 = 0; //d1是最大边,d2是次大边
for(int i=head[u];~i;i=e[i].next)
{
int v = e[i].v,w = e[i].w;
if(v==father) continue; //防止回溯
int d = dfs(v,u) + w; //d是儿子节点的最长边 + 当前节点和儿子节点的和,表示最长边
if(d > d1) {d2 = d1; d1 = d;}
else if(d > d2) d2 = d;
}
ans = max(ans,d1+d2);
return d1;
}
int main()
{
cin>>n;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dfs(1,-1);
printf("%lld",ans*10 +1ll*(ans+1)*ans / 2);
}
两次dfs
- 对任意一个点dfs,找出到该点距离最大的点,则该点为树的直径的一个端点。
- 再从该点重复dfs,找到到该点距离最大的点,则这两个点即树的直径的两个端点。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#define x first
#define y second
using namespace std;
struct edge{
int v,w;
};
const int N = 100010;
vector<edge> G[N];
int n;
int dist[N]; //dis[i]表示 dfs(u) u到其他点的距离。
void dfs(int u,int father,int dis)
{
dist[u] = dis;
for(int i=0;i<G[u].size();i++)
{
int v = G[u][i].v;
if(v!=father) //防止回溯
{
dfs(v,u,dis+G[u][i].w);
}
}
}
int main()
{
cin>>n;
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u].push_back({v,w});
G[v].push_back({u,w});
}
dfs(1,-1,0);
int u = 1;
for(int i=1;i<=n;i++)
if(dist[i] > dist[u])
u=i;
dfs(u,-1,0);
long long res = 0;
for(int i=1;i<=n;i++)
res = max(res,1ll*dist[i]);
printf("%lld",(res*res+21ll*res)/2);
}
更多推荐
所有评论(0)