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的题解:

具体在构造路径时,必须保证:
这条路径的第一个点与最后一个点,正好是与重心相连的最短的边。
当树的奇数个点,设为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;
}

浙公网安备 33010602011771号