題目的意思很明確,就是求所有樹的重心(再按字典序輸出)。
樹是很常見的資料結構,樹的重心在樹的分治中非常有用,所以對於大規模的樹快速求出重心省節時間是乙個oi選手需要考慮的問題。
那麼我們先介紹一下樹的重心。
樹的重心定義為:樹中的乙個點,刪掉該點,使剩下的樹所構成的森林中最大的子樹節點數最少。
樹的重心推論:
1.設樹上的乙個點s,樹上其餘所有點到s點的距離之和最小,那麼s就是重心。
2.樹的重心不唯一。
3.以樹的重心來做點分治,效率高如poj1741。
(見ioi2009中國國家集訓隊** 分治演算法在樹的路徑問題中的應用——漆子超)
那麼我們依靠定義來求樹的重心好了。
首先我們確定乙個根,進行一遍dfs,回溯的時候可以遞迴統計該點不同子樹所擁有的點的數量,然後再用(總節點數)減去(1)減去(子樹),就是其父親那邊的那棵樹的點的數量,區minn,最後求出即可。
***加速加速加速***
1.採用極速輸入(見我輸入輸出的**)。
2.採取陣列存邊。
加速效果:
我們看到,tle是僅採用極速輸入,用vector存邊的,效果非常差,2000ms的都沒a,不說了滿臉是淚啊。
然後呢,563ms的是僅採用陣列存邊,沒用極速輸入的。
(94ms那個不是這道題滾粗)— —
最後兩個優化都用上哈哈哈哈,157ms,該題總排名21(可惜沒進第一頁)
附**:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
typedef
long
long ll;
typedef
unsigned
long
long ull;
inline
int read()
int n;
int k;
int edge[100050];
int zhi[100050];
int zhong[100050];
int g=0;
int sum[100050];
int maxj[100050];
int minn=int_max;
void dfs(int d,int fa)
}maxj[d]=max(maxj[d],n-sum[d]-1);
minn=min(minn,maxj[d]);
sum[d]+=1;
sum[fa]+=sum[d];
maxj[fa]=max(sum[d],maxj[fa]);
return;
}int main()
dfs(1,0);
for(int i=1;i<=n;++i)
if(maxj[i]==minn)
cout
cout
/fclose(stdin);
//fclose(stdout);
return
0;}
poj3107(樹的重心)
求樹的重心。樹的重心是指去掉重心之後剩下的子樹的最大結點個數最少 樹形dp,dp i 表示以i為重心,剩下的子樹的最大結點個數,狀態轉移dp i max dp i siz j 注意用vector超時。如下 include include include include include include...
POJ 3107樹的重心
題意 找樹的重心。定義就是以重心為根的所有子樹裡面最大的最小。做法 瞎dfs一下就行了。記錄一下子樹。重點 這個題vector暴力存邊並不行。水了這麼多水題第一次被卡了。該來的總還是會來。所以用鏈式向前星來模擬鄰接表。比vector速度快的很多,也不難寫。include include includ...
POJ 3107樹的重心
題意 找樹的重心。定義就是以重心為根的所有子樹裡面最大的最小。做法 瞎dfs一下就行了。記錄一下子樹。重點 這個題vector暴力存邊並不行。水了這麼多水題第一次被卡了。該來的總還是會來。所以用鏈式向前星來模擬鄰接表。比vector速度快的很多,也不難寫。include include includ...