首页 > 其他 > 详细

POJ 1849 - Two

时间:2017-07-24 23:23:33      阅读:312      评论:0      收藏:0      [点我收藏+]

我们知道,树都有一条直径,那么,

①如果我们的起始点在直径上,那么很显然的,两辆车分别朝两个方向走,遇到直径上的分叉,就要花费分叉的总长*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 }

 

POJ 1849 - Two

原文:http://www.cnblogs.com/dilthey/p/7231438.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!