【2020.11.30提升組模擬】剪辣椒(chilli)

剪辣椒(chilli)

題目描述

在花園裏勞累了一上午以後,你決定用本身種的幹辣椒獎勵本身。
你有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

Code

#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;
}
相關文章
相關標籤/搜索