NOI2003 逃學的小孩 題解

2022-05-20 07:28:18 字數 1670 閱讀 2426

前言

>原題傳送門(洛谷)<

看了一下洛谷題面,這道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...