【HDU - 6567】Cotree(树形dp,思维)

题干:

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 uuand 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

题目大意:

给定n个点和n-2条边,已知这是两棵树。让你在每棵树中任选一点,加一条边,使得变成一棵树,要求使得树中任意两点的距离之和最小,求出这个最小值。

解题报告:

以边为单位统计贡献就行了,注意最后统计的是任意两点之间的距离和,而不是第一棵树的任意一点和第二棵树的任意一点之间的距离和。

AC代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair PII;
const int MAX = 2e5 + 5;
int n;
vector vv[MAX];
int f[MAX];
ll dp[MAX],size[MAX];
int getf(int v) {
	return f[v] == v ? v : f[v] = getf(f[v]);
}
void dfs1(int cur,int fa) {
	int up = vv[cur].size();
	size[cur] = 1;
	for(int i = 0; i>n;
	for(int i = 1; i<=n; i++) f[i] = i;
	for(int u,v,i = 1; i<=n-2; i++) {
		scanf("%d%d",&u,&v);
		vv[u].pb(v),vv[v].pb(u);u=getf(u),v=getf(v);f[v] = u;
	}
	vector rt;
	for(int i = 1; i<=n; i++) {
		if(f[i] == i) rt.pb(i);
	}
	dfs1(rt[0],-1);dfs2(rt[0],-1,size[rt[0]]);
	dfs1(rt[1],-1);dfs2(rt[1],-1,size[rt[1]]);
	ll mi0 = 1e18,mi1=1e18;
	ll tmp = 0; 
	for(int i = 1; i<=n; i++) {
		if(getf(f[i]) == getf(f[rt[0]])) mi0 = min(mi0,dp[i]);
		else mi1 = min(mi1,dp[i]);
		tmp += dp[i];
	}
	printf("%lld\n",tmp/2 + size[rt[0]]*size[rt[1]]+mi0*size[rt[1]]+mi1*size[rt[0]]);
	return 0 ;
}

 

你可能感兴趣的:(动态规划(dp),HDU,思维)