Tree and Hamilton Path

 

给你一棵树N个顶点,N-1条带权边

还有有一张 N个点的完全图,图上两点之间的边的边权为它们在树上的距离。

求最长哈密顿路径(即不重不漏恰好经过每个点一次)。

Format
Input
第一行给出数字N

接下来N-1行描述这个树,树的边权小于等于1e9

n≤1e5

Output
One integer, the sum of x and y.

Samples
输入数据 1
5
1 2 5
3 4 7
2 3 3
2 5 2
输出数据 1
38

2026的题解:

image

 具体在构造路径时,必须保证:

这条路径的第一个点与最后一个点,正好是与重心相连的最短的边。

当树的奇数个点,设为N,设第一部分有N/2+1个点,第二部分有N个点。例如下图

则构造出来的路径为5-->3-->1-->4-->2

最后要减去的边为2到5.

 

但如果2到3的边改为1.则构造出来的路径为3-->1-->4-->5-->2

 依据八中友好教室2的思路,我们知道如果希望边被经过的次数最多,要选重心点。

而这个题同样的发现,只要选择重心点,其将整个树分成上下结点数相等的两部分。

如上图,2上方面有1,5这两个点,下方有3,4这两个点。

于是在走边的时候,保证相邻的两个点来自上下部,

例如

1...4...5....3....2....1

这样的回路,或者

5...4...1....3....2...5

这样的回路

则走过的总权值就是一个固定值,即为

对于(u,v)这样的一条边,设以v为根的子树有size[v]个结点,则这条边走过的次数为2*Min(size[v],n-size[v])

证明如下:不妨设size[v]小于n-size[v]

则对于以v为子树内的结点,从它外面的点走到它时(u,v)这条边要走一次,从它再走出去,又要走一次。

于是上述成立。

以上图为例

[3,4]之间的边要走过2次

[2,3]之间的边要走过4次

于是当走成一条回路的时候,结果是个固定值为2*(5+2+7)+4*3=28+12=40

现在只需要每个点走一次,也就是说整个回路的最后一条边要被减去。

则当这条边为某条与重心直接相连的边,且边权最小时,结果最优。

 

当然如果图有两个重心的时候,减去的边权为两个重心之间的边权。。

 

一句话题解就是:

 只要将整个树的结点分成两个近可能平均的集合,然后不断从一个集合的点,走到另一个集合的点,并且走出一条回路出来,即最后一个点,又走回到第一个点。则总价是固定值,如上所分析的结论。

但如果不是这样划分的话,则走出来的路径长度是偏小的。

 

找出一条路径来:如果树只有一个重心,则树就有奇数个点(将所有点分成两个集合A,B,设重心在A集合,并且A集合多一个点设为C),则从C出发走到B集合中的一个点,再走到A集合中一个点,最后以重心点为结束点,如下图所示:

 

 

 

 

如果有两个重心,则树有偶数个点,(将所有点分成两个集合A,B,)

则从一个A集合的重心出发,走到B集合中某个点,再走到A集合中某个点,路径的结束点为B集合中的那个重心点。

例如下图

 

 

 

最终结果为总代价减去3-4之间的边长,因为3与4都是重心,它们在一条边上,所以两者之间距离是最短的。

 这个应该很好想吧,因为重心点都在靠中间的位置,如果走成

1...5...2...6...3...4....1

减去[1..4]之间的边长,那就亏大了。

 

 

#include<bits/stdc++.h>
using namespace std;
struct edge{
	int pre;
	int son;
	long long val;
}eg[200001];
int lastedge[100001],tot=0;
void addedge(int dad,int son,long long val)
{
	tot++;
	eg[tot].pre=lastedge[dad];
	lastedge[dad]=tot;
	eg[tot].son=son;
	eg[tot].val=val;
}
long long ans=0;
int node[100001],subtree[100001];
int n;
inline void dfs(int dad,int son)
{
	node[son]=1;
	for(int i=lastedge[son];i;i=eg[i].pre)
	{
		if(eg[i].son==dad)
			continue;
		dfs(son,eg[i].son);
		node[son]+=node[eg[i].son];
		subtree[son]=max(subtree[son],node[eg[i].son]);
		ans+=eg[i].val*2ll*min(node[eg[i].son],n-node[eg[i].son]);
	}
}
int dot1=0,dot2=0;
inline void gravity_find()
{
	for(int i=1;i<=n;i++)
	{
		int maxsubtree=max(subtree[i],n-node[i]);
		if(maxsubtree<=n/2)
		{
			if(!dot1)
				dot1=i;
			else
				dot2=i;
		}
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int dad,son;
		long long val;
		scanf("%d %d %lld",&dad,&son,&val);
		addedge(dad,son,val);
		addedge(son,dad,val);
	}
	dfs(0,1);
	gravity_find();
	long long minn=1e18;
	for(int i=lastedge[dot1];i;i=eg[i].pre)
	{
		if(dot2!=0&&eg[i].son==dot2)
			minn=eg[i].val;
		else if(dot2==0)
			minn=min(minn,eg[i].val);
	}
	printf("%lld\n",ans-minn);
	
	return 0;
}

 

  

 

 

 

 

 

  

 

 

  

posted @ 2022-03-08 15:26  我微笑不代表我快乐  阅读(67)  评论(0)    收藏  举报