解釈 - [[NOIP2007】コア・ネットワーク・ツリー(木直径)

問題への解決策 - [NOIP2007]ツリーネットワークコア(強化版)

この質問は、元のデータあまりにも多くの水で、ssw02トークO(n)のアプローチ


トピックの取り扱い:BZOJ1999

T =(V、E、W)は、通信非環式および有向グラフである設定(また、ツリーの非ルートとして知られている)、各正の整数の右端と、我々は、前記T(treenetwork)ツリーネットワークを呼び出しますVは、Eノードとエッジの集合を表し、Wは、セットの各辺の長さを表し、T、Nのノードをみましょう。パス:ツリーネットワークの任意の2つのノード、一つだけの単純なパスが存在するB、Dで表される(B)において、Bは、パスの各辺の長さであり、これは、パスのエンドポイントの長さです。

我々は、2つのノードBの間の距離である(B)Dを呼び出します。Pに最も近いノードまでの距離のポイントPに点Vからのパス:D(V、P)=分{D(V、U)、Uは、パスP上の接合点です}。ツリーネットワークの直径:ネットワークツリー・パスは、ツリー・ネットワークの最長直径と呼ばれています。所与のツリーネットワークTのために、直径は必ずしも一意ではないが、それは証明できる:各直径の中点は(必ずしも可能棒の内側の側のノードであることを起こるない)ユニークで、我々はこの点を呼び出しますツリー・ネットワークの中心として。

偏心ECC(F):パスの距離に最も遠いノードFからツリーネットワークTパスF、すなわち。タスク:指定されたツリーネットワークT =(V、E、W)について、パスFを求めて非負の整数の、ある(ツリーネットワーク経路のノードで終了している)パスの特定のセグメントに直径、Sを超えていない、その長さ(秒に等しくてもよい)、偏心ECC(F)最小こと。我々は、このコア(コア)のネットワークツリーT =(V、E、W)のパスを呼び出します。必要であれば、Fは、接合部に減少させることができます。

一般に、上記の定義では、コアは、必ずしも唯一ではなく、最小限偏心。次の図は、ツリーネットワークの一例を示しています。図、AB及びACは、2つの直径であり、長さは20でした。Wは、ツリーネットワークの中心点であり、辺の長さが5 EFです。あなたが核S = 11を指定した場合、ウェブパスツリーDEFG、8偏心(パスはDEFと解釈することができます)。あなたが核秒= 0(またはS = 1、S = 2)を指定すると、ツリーは、ネットワークノードF、偏心12です。

入力フォーマット
n行を有する:行1、空白で区切られた2つの正の整数NおよびS、。前記ツリーネットワークのノード数nは、sが結合した木のコアネットワークの長さです。
設定したノード番号は、1、2だった...、N。二行目からn行目には、正の整数3与えられたスペースで区切られた各ラインは、各エッジの両端点のシーケンス番号と長さを示します。例えば、「247」が7にノード2及び4を接続するエッジの長さを表します。

出力形式の
出力は、整数偏心を表します。

問題解決のためのアイデア

基本的な貪欲アルゴリズムはO(N ^ 2)、非常に単純な事実に基づいて、必要がありますし、読者に構築されています
。この質問は半分ではない、ないマルチソース最短シンクではなく、単調なキューを。
限り、我々は実際に木の直径を使い果たしたとして、直径その後、各点(U1、U2、U3、... UT) 、ランDFS2で()、缶の直径を経由せずにポイントの変化を意味します最大距離(Lon_dis [])。そして、それを維持します。
スキャンとトラバーサルのみ。
特定のプロセス:ポインタと同様に、エンド・ノード、モバイルテールエンドノードとテール・ノードから一定の距離を列挙するときのコアの境界の長さ未満です。(尾部は、エンドノードのシフトでシフトするため)。

ACコード:

#include<cstdio>
#include<cstring>
using namespace std;
const  int  MAXN = 100005 ; 
inline int  read(){
    int s = 0 ; char g=getchar() ;
    while( g>'9'||g<'0')g=getchar() ;while( g>='0'&&g<='9')s=s*10+g-'0' , g=getchar() ;
    return s ;
} 
int tot = 1 , head[ MAXN ] , to[ MAXN*2 ] , nex[ MAXN*2 ] , pre[ MAXN ] , w[ MAXN ] ;
int N , M , ans = 0 , dis[ MAXN ] , lon_dis[ MAXN ], p ;//p记录第一次的最远点 
int dia[ MAXN ] , sum[ MAXN ] ; 
bool v[ MAXN ] ; 
int max( int x , int y ){
    if( x > y )return x ;return y ; 
}
int min( int x , int y ){
    if( x > y)return y ; return x ;
}
void  add( int x , int y , int z ){
    to[ ++tot ] = y , nex[ tot ] = head[ x ] , w[ tot ] = z ,  head[ x ] = tot ; 
}
void dfs( int u , int fa ){//跑直径
    pre[ u ] = fa ;
    if( ans < dis[ u ] )ans = dis[ u ] , p = u ; 
    for( register int i = head[ u ] ; i ; i = nex[ i ] ){
        if( to[ i ] == fa )continue ;
        dis[ to[ i ] ] = dis[ u ] + w[ i ]  ;
        dfs( to[ i ] , u ) ;
    }
}
void dfs2( int u , int fa ){//跑出单点的lon_dis
    if( ans < dis[ u ] )ans = dis[ u ] , p = u ;
    for( register int i = head[ u ] ; i ; i = nex[ i ] ){
        if( to[ i ] == fa || v[ to[ i ] ] )continue ;
        dis[ to[ i ] ] = dis[ u ] + w[ i ] ; 
        dfs( to[ i ] , u ) ;
    } 
}
int main(){
    N = read() , M = read() ; int  m1 , m2 , m3 ; 
    for( register int i = 1 ; i < N ; ++i ){
        m1 = read() , m2 = read() , m3 = read() ;
        add( m1 , m2 , m3 ) , add( m2 , m1 , m3 ) ; 
    }
    dfs( 1 , 1 ) ; ans = 0 , dis[ p ] = 0 ;  
    dfs( p , p ) ; v[ p ] = true ;
    m1 = p ; 
    int  num = 1 ;
    for( register int i = m1 ; i ; i = pre[ i ] , ++num ){
        dia[ num ] = i ;
        if( pre[ i ] == i )break ;
        for( register int k = head[ i ] ; k ; k = nex[ k ] )
            if( to[ k ] == pre[ i ] )sum[ num+1 ] = sum[ num ] + w[ k ] ;//sum是直径距离的前缀和,方便查距离
        v[ pre[ i ] ]  = true ; 
    }
    ans = 0 , dis[ p ] = 0 ;
    dfs2( m1 , m1 ) ; lon_dis[ p ] = dis[ p ] ;  
    for( register int i = m1 ; i ; i = pre[ i ] ){
        ans = 0 , dis[ i ] = 0 , p = 0 ;
        dfs2( i , i ),lon_dis[ i ] = dis[ p ] ; 
        if( pre[ i ] == i )break ; 
    }
    int  ECC = (1<<30) , tail = 1  ;//指针往后推
    for( register int i = 1 ; i <= num ; ++i ){//写得过丑,请屏蔽
        int anns = 0 ;
        while( sum[ i ] - sum[ tail ] > M && tail <= num )tail++ ;
        if( tail > num )break ;
        for( register int j = tail ; j <= i ; ++j )anns = max( anns , lon_dis[ j ] ) ;
        anns = max( sum[ tail ]-sum[ 1 ] , max( sum[ num ]-sum[ i ] , anns ) ) ;//前缀和之差为两点距离
        ECC = min( anns , ECC ) ;
    }
    printf("%d",ECC) ;
    return 0 ;
}
/*
5 2
1 2 5
2 3 2
2 4 4
2 5 3
*/

私はあなたに感謝するssw02をよくお読み、首長が不備を指摘願っています

おすすめ

転載: www.cnblogs.com/ssw02/p/11234827.html