BZOJ1509 [NOI2003]逃学的小孩 树型DP

题目:

分析:

  首先明确我们是要求 min(dist[C][A],dist[C][B])+dist[A][B].

  我们把C当成树根,第一我们可以发现min里面取dist[C][A]或者dist[C][B]其实是一个意思(因为可以交换)。

  接着可以发现dist[A][B]实际上是这棵树的直径。如果不是,那么答案一定不是最优的。我们可以这样去想:

    如果dist[A][B]不是直径,那么一定有dist[C][A']使得比dist[C][A]更优,而且A'一定是直径的一个端点:-)。加号的前面和后面都不是最优的,那么答案也不是最优的。

  所以我们可以先处理出树的直径,接着枚举点C使得它到两个端点的距离的最小值最大。

  时间复杂度O(n),空间复杂度O(n)。  

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<vector>
 6 using namespace std;
 7  
 8 typedef long long ll;
 9  
10 struct edge{
11     ll to,w;
12 };
13  
14 const ll maxn = 200010;
15  
16 ll n,m;
17 vector <edge> g[maxn];
18 ll arr[maxn],dep[maxn];
19  
20 void dfs(int now,ll data){
21     arr[now] = 1;
22     dep[now] = min(dep[now],data);
23     for(int i=0;i<g[now].size();i++){
24     if(arr[g[now][i].to]) continue;
25     dfs(g[now][i].to,g[now][i].w+data);
26     }
27     arr[now] = 0;
28 }
29  
30 int get_max(){
31     dep[0] = 0;
32     int maxx = 0;
33     for(int i=1;i<=n;i++){
34     if(dep[maxx] < dep[i]) maxx = i;
35     }
36     return maxx;
37 }
38  
39 void read(){
40     scanf("%lld%lld",&n,&m);
41     for(ll i=1;i<=m;i++){
42     ll x,y,c; scanf("%lld%lld%lld",&x,&y,&c);
43     g[x].push_back((edge){y,c});
44     g[y].push_back((edge){x,c});
45     }
46 }
47  
48 void work(){
49     memset(dep,127/3,sizeof(dep));
50     dfs(1,0);//get the farthest point in tree
51     ll ans=0,t1 = get_max();
52     memset(dep,127/3,sizeof(dep));
53     dfs(t1,0);//another point
54     ll t2 = get_max();
55     ans += dep[t2];//zhijing
56     dfs(t2,0);
57     ll maxx = 0;
58     for(int i=1;i<=n;i++)
59     maxx = max(maxx,dep[i]);
60     ans += maxx; // farthest dian for zhijing
61     printf("%lld",ans);
62 }
63  
64 int main(){
65     read();
66     work();
67     return 0;
68 }

 

posted @ 2017-05-27 07:45  社会主义市场经济  阅读(169)  评论(0编辑  收藏  举报