1. 程式人生 > 實用技巧 >試題 歷屆試題 大臣的旅費(求樹的直徑,兩次dfs)

試題 歷屆試題 大臣的旅費(求樹的直徑,兩次dfs)

問題描述

很久以前,T王國空前繁榮。為了更好地管理國家,王國修建了大量的快速路,用於連線首都和王國內的各大城市。

為節省經費,T國的大臣們經過思考,制定了一套優秀的修建方案,使得任何一個大城市都能從首都直接或者通過其他大城市間接到達。同時,如果不重複經過大城市,從首都到達每個大城市的方案都是唯一的。

J是T國重要大臣,他巡查於各大城市之間,體察民情。所以,從一個城市馬不停蹄地到另一個城市成了J最常做的事情。他有一個錢袋,用於存放往來城市間的路費。

聰明的J發現,如果不在某個城市停下來修整,在連續行進過程中,他所花的路費與他已走過的距離有關,在走第x千米到第x+1千米這一千米中(x是整數),他花費的路費是x+10這麼多。也就是說走1千米花費11,走2千米要花費23。

J大臣想知道:他從某一個城市出發,中間不休息,到達另一個城市,所有可能花費的路費中最多是多少呢?

輸入格式

輸入的第一行包含一個整數n,表示包括首都在內的T王國的城市數

城市從1開始依次編號,1號城市為首都。

接下來n-1行,描述T國的高速路(T國的高速路一定是n-1條)

每行三個整數Pi, Qi, Di,表示城市Pi和城市Qi之間有一條高速路,長度為Di千米。

輸出格式

輸出一個整數,表示大臣J最多花費的路費是多少。

樣例輸入1 5
1 2 2
1 3 1
2 4 5
2 5 4 樣例輸出1 135 輸出格式

大臣J從城市4到城市5要花費135的路費。

題解:求兩點間的最長路,剛開始每個點去暴搜,很自然地t了。 後來看了網上一些資料才知道是進行兩次dfs,第一次dfs任意一個頂點出發到的最遠的點即是直徑的一端, 記錄這個端點去找最遠的路徑,即是樹的直徑,也就是本題要找的最長路。 比如樣例

從1出發最遠的點是4,從2出發最遠的點是4,從3出發最遠的點是4,從4出發最遠的點是5,從5出發最遠的點是4.

無論哪個點出發得到的最遠點都是直徑的端點。得到端點後再進行dfs,即是最遠的路徑。

code:

#include<bits/stdc++.h>
using namespace std;
int maxx=-1;
const int maxn=1e6;
vector<pair<int,int> >dis[maxn];
int vis[maxn];
int pos;
void dfs(int m,int cost){
    if(cost>maxx){
        maxx
=cost; pos=m; } for(int i=0;i<dis[m].size();i++){ if(!vis[dis[m][i].first]){ vis[dis[m][i].first]=1; dfs(dis[m][i].first,cost+dis[m][i].second); vis[dis[m][i].first]=0; } } } int main(){ int n,a,b,t;cin>>n; for(int i=0;i<n-1;i++){ scanf("%d%d%d",&a,&b,&t); dis[a].push_back(make_pair(b,t)); dis[b].push_back(make_pair(a,t)); } vis[1]=1; dfs(1,0); fill(vis,vis+maxn,0); vis[pos]=1; maxx=-1; dfs(pos,0); long long int sum=0; for(int i=1;i<=maxx;i++){ sum+=10+i; } cout<<sum<<endl; return 0; }

較好的分析