Cotree

Cotree

Avin has two trees which are not connected. He asks you to add an edge between them to make them connected while minimizing the function ∑ni=1∑nj=i+1dis(i,j)∑i=1n∑j=i+1ndis(i,j), where dis(i,j)dis(i,j) represents the number of edges of the path from ii to jj. He is happy with only the function value.

Input

The first line contains a number n (2<=n<=100000)n (2<=n<=100000). In each of the following n−2n−2 lines, there are two numbers uu and vv, meaning that there is an edge between uu and vv. The input is guaranteed to contain exactly two trees.

Output

Just print the minimum function value.

Sample Input

3
1 2

Sample Output

4

这道题就是找两棵树的重心,然后将两个重心相连得到的最小贡献值。

首先重心的定义:树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。

将两棵树的重心相连,即得到合法的树。

其中一条边的贡献值=左结点数*右结点数*这条边的权值,这里我们默认每条边的权值都为1.

 首先将数的关系存进vector中,选定1为其所在的树的根结点,然后从1结点遍历1所在的整棵树,求出其每条边的贡献值,并记录其结点个数,然后将遍历到的另一棵树的第一个结点作为第二棵树的根,然后分别求出两棵树的每条边的贡献值,再加上两棵树重心相连的边的贡献值,(其中非根节点的边的贡献值的公式并不理解)

以下是ac代码:

#include
using namespace std;
const int maxn=1e5+7;
typedef long long ll;
int n;
ll fa[maxn],si[maxn],f[maxn],g[maxn];//fa:父结点,si:该树结点的个数,f:该结点子树边的贡献值,g:非子树边的贡献值 
vector ve[maxn];

void dfsfind(int x){
	si[x]=1;//至少包含他本身 
	f[x]=0;//初始贡献值为0 
	int i;
	for(auto i:ve[x]){

		if(i!=fa[x]){ 
			fa[i]=x;
			dfsfind(i);
			si[x]+=si[i];
			f[x]+=f[i]+si[i]*(n-si[i]); 
		}
	} 
}

ll dfsvalue(int x,int root,ll sum){
//	cout<<"loop"<>n;
//	ve.resize(n+1); 
//	cout<<"****";
	for(int i=0;i<=n;i++){
		fa[i]=-1;//初始化父结点 
	}

	for(int i=0;i<(n-2);i++){
		int x,y;
		cin>>x>>y;
		ve[x].push_back(y); 
		ve[y].push_back(x);
	} 
	int root1=1,root2;
	fa[1]=1;//将1结点为1在的树的根 
	dfsfind(1);
	ll sum1=si[1],sum2=n-si[1];//两棵树的结点数 
	for(int i=1;i<=n;i++){
		if(fa[i]==-1){//该结点位于另一棵没有遍历的树 
			fa[i]=i;
			root2=i;
			dfsfind(i);
			break; 
		}
	}	 
	
	cout<

 

你可能感兴趣的:(算法)