首页 > 技术文章 > 树的直径-蓝桥杯大臣的旅费

savennist 2020-03-25 20:55 原文

蓝桥杯大臣的旅费

树的直径理论

首先从u dfs找到最远点v ,然后从v开始,dfs找到的最远点一定是树的直径
证明:
如果u->v 和树的直径没有公共点,则可以从树的直径终点到u引一条边,树直径变长了,矛盾
假设交点为k,那么k->v (或者就是v本身) 一定是树直径的一部分,(最优子结构)
这样就证明了v一定在树的直径的端点处,(为什么是端点,因为u->v是最远的,一定是叶子节点)

代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <vector>
 5 using namespace std;
 6  
 7 const int maxn = 1e6 + 5;
 8 int n, max_dis = -1, vis[maxn], start;
 9 vector<int> g[maxn];
10 vector<int> e[maxn];
11  
12 int cal(int x)
13 {
14     int res = 0;
15     for(int i=1;i<=x;++i)res+=(i+10);
16     return res;
17 }
18 
19 void dfs(int u,int sum)
20 {
21     vis[u] = 1;
22     if(sum>max_dis)
23     {
24         max_dis = sum;
25         start = u;
26     }
27     for(int i=0;i<g[u].size();++i)
28     {
29         if(!vis[g[u][i]]) dfs(g[u][i],sum+e[u][i]);
30     }
31 }
32  
33 int main()
34 {
35     freopen("input.txt","r",stdin);
36     cin>>n;
37     int u,v,k;
38     for (int i=0;i<n-1;++i)
39     {
40         cin>>u>>v>>k;
41         g[u-1].push_back(v-1);
42         g[v-1].push_back(u-1);
43         e[u-1].push_back(k);
44         e[v-1].push_back(k);
45     }
46     dfs(0,0);
47     //任意取一个点寻找最远的结点start
48     max_dis=-1;
49     memset(vis,0,sizeof(vis));
50     dfs(start,0);//从start开始求解树的直径
51     //重置深搜时使用的变量
52     cout<<cal(max_dis)<<endl;
53     return 0;
54 }

OK

推荐阅读