前言
>原題傳送門(洛谷)<
看了一下洛谷題面,這道noi的題竟然是藍的(惡評?),做了一下好像確實是藍的...
解法
思路非常簡單,找道樹的直徑,然後答案是直徑長度加上最大的min(dis[pos1], dis[pos2]),pos1和pos2是指定的任意一條直徑的兩個端點,dis是距離
證明
鑑於這是一棵樹(原題面:可以保證,任兩個居住點間有且僅有一條通路。)
因此,我們最大的方案必然包含一條直徑
可以稍加思考,如果不是直徑的話一定能找到一種取直徑的方法比它更大...
那麼再任意找另乙個點,因為要滿足"如果a距離c比b距離c近走a,否則走b",所以任意乙個點的貢獻為min(dis[pos1], dis[pos2])。
題目要求最大的,所以取最大的min(dis[pos1], dis[pos2])
**
樹的直徑顯然只需要乙個dfs,求解也只需要乙個dfs,所以共計兩個dfs
#include #include #define ll long long
using namespace std;
ll read()
struct edge edges[400005];
int head[200005], edge_num;
void addedge(int u, int v, ll w);
head[u] = edge_num;
}ll dis[200005];
ll dis2[200005][2];
void getdis(int u, int fa, ll vl)
}void getdis2(int u, int fa, ll vl, int op)
}int main()
getdis(1, 1, 0);
int pos1; ll _max = -1;
for (int i = 1; i <= n; ++i)
if (dis[i] > _max)
_max = dis[i], pos1 = i;
getdis(pos1, pos1, 0);
int pos2; _max = -1;
for (int i = 1; i <= n; ++i)
if (dis[i] > _max)
_max = dis[i], pos2 = i;
getdis2(pos1, pos1, 0, 0);
getdis2(pos2, pos2, 0, 1);
ll _max2 = -1;
for (int i = 1; i <= n; ++i)
_max2 = max(_max2, ((dis2[i][0] > dis2[i][1]) ? dis2[i][1] : dis2[i][0]));
printf("%lld", _max + _max2);
return 0;
}
備註
求樹的直徑:從任意一點開始dfs,找到最遠點pos1,再從pos1開始dfs找到最遠點pos2,
pos1和pos2即為樹的直徑
證明略(易證)
NOI2003 逃學的小孩
演算法 最短路 樹的直徑 難度 noip 注意 多年oi一場空,不開long long見祖宗!如果不開long long,應該會被卡到60分!注意 dfs找樹的直徑時,傳的引數 d 也要開long long哦!首先,因為無論如何答案都會包括a到b的dis,所以我們先用2遍dfs找到dis a b 的...
NOI2003 逃學的小孩
傳送門 here 題意 給出一棵樹 帶權 要從乙個節點c先走到距離它近的乙個節點b,再走到a,要求最壞情況下的總路程 即最長 解題思路 乍一看,a,b,c都沒給出,這怎麼求?不妨設距離c較近的點位a。分析發現,無論怎樣,a b是一定要走的。那麼如何能讓樹上任意兩點間距離最大呢?不難發現a,b就是該樹...
NOI2003 逃學的小孩
chris家的 鈴響起了,裡面傳出了chris的老師焦急的聲音 喂,是chris的家長嗎?你們的孩子又沒來上課,不想參加考試了嗎?一聽說要考試,chris的父母就心急如焚,他們決定在盡量短的時間內找到chris。他們告訴chris的老師 根據以往的經驗,chris現在必然躲在朋友shermie或ya...