木を2回精査すれば簡単です。
木を2往復するので計算量はBigO(2*頂点数)です。
速すぎて一位タイです。
これ以上シンプルな考え方もないし計算に必要なデータを集めるのに最初の1周。
確定するのにもう一周必要なので、私の発想は理論値でしょう。
多分コード実行速度一位の方と同じ発想になってると思います。
着想を得るのに10分かかりました。
実装するとき考え抜けに気付かず1時間かかりました。
テストに20分かかりました(コードの修正)。
木の根元を点0として枝先から根元へ向かう計算に一周目を。
点0から枝先に向かう計算で2周目を使います。
例えば木を一周した結果根元で14,17,22という高さになる枝が3つ出ていたら。
14や17に向かう時は22を最大として2周目を回ればいいですし。
22の枝先に向かう時は17を最大として2周目の22の先の枝先を回ればいいわけです。
#include<stdio.h>
#include<map>
#include<string.h>
#include<queue>
#include<set>
#include<algorithm>
const int LIMIT=10000;
std::map<int,int> tree[LIMIT];
int ans[LIMIT];
int maxWs1[LIMIT];
int maxWs2[LIMIT];
int maxPs1[LIMIT];
int maxPs2[LIMIT];
int saiki(int p,int old,int maxW1){
std::map<int,int>::iterator it;
int maxW2=0;
int maxP1=old;
int maxP2=-1;
for(it=tree[p].begin();it!=tree[p].end();it++){
if((*it).first==old)continue;
int temp=saiki((*it).first,p,maxW1+(*it).second);
if(temp>=maxW1){
maxP2=maxP1;
maxP1=(*it).first;
maxW2=maxW1;
maxW1=temp;
}else if(temp>=maxW2){
maxW2=temp;
maxP2=maxP1;
}
}
maxPs1[p]=maxP1;
maxPs2[p]=maxP2;
maxWs1[p]=maxW1;
maxWs2[p]=maxW2;
ans[p]=maxW1;
if(old==maxP1){
return maxW2+tree[p][old];
}else{
return maxW1+tree[p][old];
}
}
void saiki2(int p,int old,int maxW){
std::map<int,int>::iterator it;
for(it=tree[p].begin();it!=tree[p].end();it++){
if((*it).first==old)continue;
int nextP=(*it).first;
int temp;
if(nextP==maxPs1[p]){
saiki2(nextP,p,std::max(maxWs2[p],maxW)+(*it).second);
}else{
saiki2(nextP,p,std::max(maxWs1[p],maxW)+(*it).second);
}
}
ans[p]=std::max(ans[p],maxW);
}
int main(){
int n;
scanf("%d",&n);
memset(ans,0,sizeof(ans));
memset(maxWs1,0,sizeof(maxWs1));
memset(maxWs2,0,sizeof(maxWs2));
for(int i=0;i<n-1;i++){
int s,t,w;
scanf("%d %d %d",&s,&t,&w);
tree[s][t]=w;
tree[t][s]=w;
}
saiki(0,-1,0);
saiki2(0,-1,0);
for(int i=0;i<n;i++)printf("%d\n",ans[i]);
}
最終更新:2015年07月24日 20:26