「日常訓練」Balancing Act(POJ-1655)
阿新 • • 發佈:2018-11-02
題意與分析
樹的重心板子題。
值得考慮的是,重心究竟有哪些優秀的性質?
這裡是一些網上能看到的性質:
- (判定性質)找到一個點,其所有的子樹中最大的子樹節點數最少(子樹可以“倒著看”),那麼這個點就是這棵樹的重心。
- 以這個點為根,那麼所有的子樹(不算整個樹自身)的大小都不超過整個樹大小的一半。
- 樹中所有點到某個點的距離和中,到重心的距離和是最小的;如果有兩個重心,那麼他們的距離和一樣。
- 把兩個樹通過一條邊相連得到一個新的樹,那麼新的樹的重心在連線原來兩個樹的重心的路徑上。
- 把一個樹新增或刪除一個葉子,那麼它的重心最多隻移動一條邊的距離。
利用判定性質能夠在一次dfs內完成樹的重心的判斷。定義\(dp[i]\)
相關題目見之後的題解。
程式碼
#include <iostream> #include <cstring> #include <utility> #include <vector> #define INF 0x3f3f3f3f #define PB push_back #define MP make_pair #define fi first #define se second #define rep(i,a,b) for(repType i=(a); i<=(b); ++i) #define per(i,a,b) for(repType i=(a); i>=(b); --i) #define ZERO(x) memset(x, 0, sizeof(x)) #define MS(x,y) memset(x, y, sizeof(x)) #define ALL(x) (x).begin(), (x).end() #define QUICKIO \ ios::sync_with_stdio(false); \ cin.tie(0); \ cout.tie(0); #define DEBUG(...) fprintf(stderr, __VA_ARGS__), fflush(stderr) using namespace std; typedef int repType; const int MAXN=20005; vector<int> G[MAXN]; int cnt[MAXN],dp[MAXN]; int n; int dfs(int x) { if(cnt[x]!=0) return 0; cnt[x]=1; rep(i,0,int(G[x].size())-1) { cnt[x]+=dfs(G[x][i]); dp[x]=max(dp[x],cnt[G[x][i]]); } dp[x]=max(dp[x],n-cnt[x]); return cnt[x]; } int main() { int T; cin>>T; while(T--) { cin>>n; rep(i,1,n) G[i].clear(); rep(i,1,n-1) { int u,v; cin>>u>>v; G[u].PB(v); G[v].PB(u); } MS(cnt,0); MS(dp,-1); rep(i,1,n) if(!cnt[i]) dfs(i); int ans=INF,pos=0; rep(i,1,n) if(ans>dp[i]) ans=dp[pos=i]; cout<<pos<<" "<<ans<<endl; } return 0; }