在花園裏勞累了一上午以後,你決定用本身種的幹辣椒獎勵本身。
你有n個辣椒,這些辣椒用n-1條繩子鏈接在一塊兒,任意兩個辣椒經過用若干個繩子相連,即造成一棵樹。
你決定分三餐吃完這些辣椒,所以須要剪斷其中兩根繩子,從而獲得三個組成部分,每一餐吃一個組成部分便可。
每一餐不能夠太辣,因此你會尋找一個剪繩子的方法,使得最大組成部分和最小組成部分的辣椒數量差最小。計算出這個最小差值。node
輸入文件名爲chilli.in。
第一行一個整數n,表示辣椒的數量。辣椒從1到n進行編號。
下面n-1行每一行包含兩個整數x和y(1≤x,y≤n),表示辣椒x和辣椒y直接用一根繩子相連。ios
輸出文件名爲chilli.out。
輸出最小差值。spa
題目大意:刪掉一棵樹上的兩條邊使得造成的三棵樹裏\(size\)最大的減\(size\)最小的差值最小,問最小差值
先求出以每一個點爲根的子樹的大小\(size_i\)(假定1爲整棵樹的根)
而後枚舉每一個點(用\(dfs\),在到每一個點的時候就計算貢獻,即刪除當前點與父親的邊,作完以後把\(n-size_x\)加到\(set\),結束後從\(set\)中移除),刪掉它與它父親的邊,這時將整棵樹分紅兩部分:\(size_x\)和\(n-size_x\),而後在\(n-size_x\)裏找到\(\lceil\dfrac{n-size_x}{2}\rceil\)的前驅後繼,這裏能夠用\(set\)裏的\(lower\_bound\)(不會用\(set\)能夠自行搜索,這裏推薦一篇寫的比較好的文章https://blog.csdn.net/qq_34243930/article/details/81481929)。關於另外一條邊,有兩種狀況,一種是祖先邊,上面已經計算,另外一種是非祖先邊,能夠再用一個\(dfs\),但與上面有所不一樣,這裏是刪除當前點與兒子的邊,而後結束後加入\(size_x\).net
#include<set> #include<cstdio> #include<cstring> #include<iostream> #define inf 2147483600 using namespace std; struct node { int next,to,head; }a[400001]; int n,x,y,ans,tot,size[200001]; multiset<int> q; multiset<int>::iterator it; void add(int x,int y) { a[++tot].to=y; a[tot].next=a[x].head; a[x].head=tot; } void getsize(int now,int fa) { size[now]=1; for (int i=a[now].head;i;i=a[i].next) { if (a[i].to==fa) continue; getsize(a[i].to,now); size[now]+=size[a[i].to]; } } int getans(int x,int y,int z) {return max(x,max(y,z))-min(x,min(y,z));} void calc(int x) { int p=n-size[x]; it=q.lower_bound((p+1)>>1); if (it!=q.end()) ans=min(ans,getans(size[x],p-*it,*it)); if (it!=q.begin()) it--,ans=min(ans,getans(size[x],p-*it,*it)); it=q.lower_bound(max(size[x],p-size[x])); if (it!=q.end()) ans=min(ans,*it*2-p); } void dfs1(int now,int fa) { calc(now); q.insert(n-size[now]); for (int i=a[now].head;i;i=a[i].next) { if (a[i].to==fa) continue; dfs1(a[i].to,now); } q.erase(n-size[now]); } void dfs2(int now,int fa) { for (int i=a[now].head;i;i=a[i].next) { if (a[i].to==fa) continue; calc(a[i].to); dfs2(a[i].to,now); } q.insert(size[now]); } int main() { freopen("chilli.in","r",stdin); freopen("chilli.out","w",stdout); scanf("%d",&n); for (int i=1;i<n;++i) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } ans=inf; getsize(1,0); dfs1(1,0); dfs2(1,0); printf("%d\n",ans); fclose(stdin); fclose(stdout); return 0; }