我们知道,树都有一条直径,那么,
①如果我们的起始点在直径上,那么很显然的,两辆车分别朝两个方向走,遇到直径上的分叉,就要花费分叉的总长*2的路程来遍历这些分叉,而直径上的边都只需要走一遍即可
②而如果我们的起始点不在直径上,那么他们两辆车只需要先把这个分叉遍历一遍,最后回到直径上,那么又可以按①的过程,两辆车朝两边走。
综上,我们就可以知道,这样需要走过的总路程 ans = "直径长度" + 2 * "所有分叉上边的长度总和",换句话说,就是ans = 2 * "所有边的长度总和" - "直径长度";
至于,求树的直径,我们可以有两种方法:
参考:http://blog.csdn.net/tc_to_top/article/details/47002255
首先是两次DFS的过程:
1 #include<cstdio> 2 #include<vector> 3 #define MAXN 100000+5 4 using namespace std; 5 struct Edge{ 6 int u,v,w; 7 }; 8 vector<Edge> adj[MAXN]; 9 int n,s,d[MAXN],sum; 10 void dfs(int now,int par) 11 { 12 for(int i=0;i<adj[now].size();i++) 13 { 14 Edge edge=adj[now][i]; 15 int next=edge.v; 16 if(next==par) continue; 17 d[next]=d[now]+edge.w; 18 dfs(next,now); 19 } 20 } 21 int main() 22 { 23 while(scanf("%d%d",&n,&s)!=EOF) 24 { 25 sum=0; 26 for(int i=1;i<=n;i++) adj[i].clear(); 27 for(int i=1;i<n;i++) 28 { 29 int u,v,w; 30 scanf("%d%d%d",&u,&v,&w); 31 sum+=w; 32 adj[u].push_back((Edge){u,v,w}); 33 adj[v].push_back((Edge){v,u,w}); 34 } 35 d[s]=0; 36 dfs(s,-1); 37 int max=0,max_i; 38 for(int i=1;i<=n;i++) 39 { 40 if(max<d[i]) 41 { 42 max=d[i]; 43 max_i=i; 44 } 45 } 46 d[max_i]=0; 47 dfs(max_i,-1); 48 int diameter=0; 49 for(int i=1;i<=n;i++) if(diameter<d[i]) diameter=d[i]; 50 printf("%d\n",2*sum-diameter); 51 } 52 }
至于树形DP的方法,比较难想,但其实和两次DFS异曲同工,任何一个点,可以在DFS过程中转到其所在分叉链接在直径的那个节点上,而这个节点的最大和次大相加,就可以得到直径。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #define MAXN 100000+5 5 using namespace std; 6 struct Edge{ 7 int u,v,w; 8 }; 9 vector<Edge> adj[MAXN]; 10 int n,s,sum,diameter; 11 int dp[MAXN][2]; 12 void dfs(int now,int par) 13 { 14 for(int i=0;i<adj[now].size();i++) 15 { 16 Edge edge=adj[now][i]; 17 int next=edge.v; 18 if(next==par) continue; 19 dfs(next,now); 20 if(dp[now][0] < dp[next][0]+edge.w) // ( "其某个孩子的最大"+"其与孩子的距离" ) > "最大" > "次大" 21 { 22 dp[now][1] = dp[now][0]; 23 dp[now][0] = dp[next][0] + edge.w; 24 } 25 else if(dp[now][1] < dp[next][0]+edge.w) // "最大" > ( "其某个孩子的最大"+"其与孩子的距离" ) > "次大" 26 { 27 dp[now][1] = dp[next][0]+edge.w; 28 } 29 } 30 if(diameter<dp[now][0]+dp[now][1]) diameter=dp[now][0]+dp[now][1]; 31 } 32 int main() 33 { 34 while(scanf("%d%d",&n,&s)!=EOF) 35 { 36 diameter=sum=0; 37 for(int i=1;i<=n;i++) adj[i].clear(); 38 memset(dp,0,sizeof(dp)); 39 for(int i=1;i<n;i++) 40 { 41 int u,v,w; 42 scanf("%d%d%d",&u,&v,&w); 43 sum+=w; 44 adj[u].push_back((Edge){u,v,w}); 45 adj[v].push_back((Edge){v,u,w}); 46 } 47 dfs(s,-1); 48 printf("%d\n",2*sum-diameter); 49 } 50 }
原文:http://www.cnblogs.com/dilthey/p/7231438.html