AtCoder Grand Contest 018--D题

D - Tree and Hamilton Path


Time limit : 2sec / Memory limit : 256MB

Score : 1100 points

Problem Statement

There is a tree with N vertices, numbered 1 through N. The i-th edge in this tree connects Vertices Ai and Bi and has a length of Ci.

Joisino created a complete graph with N vertices. The length of the edge connecting Vertices u and v in this graph, is equal to the shortest distance between Vertices uand v in the tree above.

Joisino would like to know the length of the longest Hamiltonian path (see Notes) in this complete graph. Find the length of that path.

Notes

Hamiltonian path in a graph is a path in the graph that visits each vertex exactly once.

Constraints

  • 2N105
  • 1Ai<BiN
  • The given graph is a tree.
  • 1Ci108
  • All input values are integers.

Input

Input is given from Standard Input in the following format:

N
A1 B1 C1
A2 B2 C2
:
AN1 BN1 CN1

Output

Print the length of the longest Hamiltonian path in the complete graph created by Joisino.


Sample Input 1

Copy
5
1 2 5
3 4 7
2 3 3
2 5 2

Sample Output 1

Copy
38

The length of the Hamiltonian path 5 → 3 → 1 → 4 → 2 is 5+8+15+10=38. Since there is no Hamiltonian path with length 39 or greater in the graph, the answer is38.


Sample Input 2

Copy
8
2 8 8
1 5 1
4 8 2
2 5 4
3 8 6
6 8 9
2 7 12

Sample Output 2

Copy
132

题解:

case1:存在一条边,移除这条边后,树分成两个顶点数目相同的子树。如1-2-3-4-5-6 树形图,拆掉3-4这条边,交叉的访问这两个集合中的点,最优的顶点访问序列就是:3->6->2->5->1->4,一共经过17条边;

case2:存在一个顶点G,移除这个顶点以及与该点相连的边,图分成K个部分,每个部分的顶点数目Ti<=N/2,(i=1,...K)。那么,我们把G点作为访问的第一个点,再从这K个连通部分中,找到一个点v作为最后一个访问的顶点,要求该顶点v需与G直接相连。这样,就可以构造一个序列,使得属于同一个连通集里的两个顶点不会相邻。



#include <iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<map>
#include<cmath>
using namespace std;
#define LL long long
#define rep(i,a,n) for(int i=a;i<n;++i)
#define per(i,a,n) for(int i=n-1;i>=a;--i)
#define mem(a,t) memset(a,t,sizeof(a))
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(v) v.begin(),v.end()
#define sz(v) ((int)sizeof(v))
const int inf=1e9;
const int N=1e5+5;
int n,splen=0,spv;
LL ans=0;
vector<pair<int,int> >g[N];
int c[N];

void dfs(int u,int pre,int len){
    c[u]=1;
    int v,w,child=0;
    for(int i=0;i<g[u].size();++i){
        v=g[u][i].fi;
        if(v==pre) continue;
        dfs(v,u,g[u][i].se);
        c[u]+=c[v];
        child=max(child,c[v]);
    }
    child=max(child,n-c[u]);
    if(c[u]*2==n){    //case1
        splen=len;
    }
    if(child<=n/2){         //case2
        spv=u;               //特殊点G,
    }
    ans+=2ll*len*min(c[u],n-c[u]);
}

int main(){
    ios_base::sync_with_stdio(false);
    cin>>n;
    int u,v,w;
    rep(i,0,n-1){
        cin>>u>>v>>w;
        g[u].pb(mp(v,w));
        g[v].pb(mp(u,w));
    }
    dfs(1,0,0);
    if(splen){            //case1
        cout<<ans-splen<<endl;
    }
    else{              //case2
        int mi=1e9;
        for(int i=0;i<g[spv].size();++i){    //找到和特殊点相邻的最小边e
            mi=min(mi,g[spv][i].se);
        }
        cout<<ans-mi<<endl;
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/u011721440/article/details/76209038