题意:给你一颗n个节点n-1条边的树,每条边都有一个权值,现在让你任意移动一条边然后把这条边连接到任意两个点上,最后问你怎样移动才能使树上相距最远的两个点距离最小。
思路:先求出树的最长路,然后枚举移动最长路上的所有边,移走这条边后,原树必定分为不连接的两颗子树,分别求这两颗子树的最长路,然后分别找到两颗子树最长路上靠近中点的点,那么最长路有三种情况:假设这条边为 u -> v
1.u的左子树的直径;
2.v的右子树的直径;
3.u的左子树的直径上中点分割的最长路径 + v的右子树的直径上中点分割的最长路径 + 边权
每枚举一条边,就取这三种情况的最大值;
需要注意的事:两棵子树的最长路,一定是以整棵树的最长路的两个端点为起始点的,因此只需要预处理出所有点到两个端点的距离,然后根据删除的最长路边求两颗子树中的最大值即可。
所以我们只需2次BFS就够了;
我感觉我的代码很简短:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define N 3000
int head[N],cnt;
void ini()
{
memset(head,-1,sizeof(head));
cnt=0;
}
struct Edge
{
int next,w,to;
}e[N*2];
void Add_edge(int a, int b, int c)
{
e[cnt].to=b;e[cnt].w=c;
e[cnt].next=head[a];
head[a]=cnt++;
}
int dis1[N],dis2[N],fa2[N],vis[N],fa1[N],max_dis,max_id;
void BFS(int root, int dis[], int fa[])
{
max_dis=0;max_id=root;fa[root]=root;
memset(vis,0,sizeof(vis));
dis[root]=0;
queue <int> Q;
Q.push(root);
while(!Q.empty())
{
int u=Q.front();Q.pop();
vis[u]=1;
for(int i = head[u]; i != -1; i = e[i].next)
{
int v=e[i].to;
if(vis[v])continue;
dis[v]=dis[u]+e[i].w;
if(max_dis<dis[v]){max_dis=dis[v],max_id=v;}
fa[v]=u;
Q.push(v);
}
}
}
void dfs(int u, int pre, int dis[]) //dis1==s为起点 dis2==t为起点
{
for(int i = head[u]; i != -1; i = e[i].next)
{
int v=e[i].to;
if(v==pre)continue;
dfs(v,u,dis);
if(max_dis<dis[v]){max_dis=dis[v];max_id=v;}
}
}
int main()
{
int T;scanf("%d",&T);
for(int g = 1; g <= T; g++)
{
ini();
int n;scanf("%d",&n);
for(int i = 1; i < n; i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
Add_edge(a,b,c);
Add_edge(b,a,c);
}
int s=0,t;
BFS(s,dis1,fa1);
s=max_id;
BFS(s,dis1,fa1);
t=max_id;
BFS(t,dis2,fa2);
int ans=0x7fffffff;
for(int i = t; i != s; i=fa1[i])
{
int tmp_ans;
int len=dis2[fa1[i]]-dis2[i];
max_dis=dis2[i];
max_id=i;
dfs(i,fa1[i],dis2);
tmp_ans=max_dis;
int top=max_dis/2;
int zhongdian,max1,max2;
int tmp=0x7fffffff;
zhongdian=max_id;
for(int j = max_id; j != t; j=fa2[j])
if(abs(dis2[j]-top)<tmp){tmp=abs(dis2[j]-top);zhongdian=j;}
max1=max(dis2[max_id]-dis2[zhongdian],dis2[zhongdian]);
max_dis=dis1[fa1[i]];
max_id=fa1[i];
dfs(fa1[i],i,dis1);
tmp_ans=max(tmp_ans,max_dis);
top=max_dis/2;
tmp=0x7fffffff;
zhongdian=max_id;
for(int j = max_id; j != s; j=fa1[j])
if(abs(dis1[j]-top)<tmp){tmp=abs(dis1[j]-top);zhongdian=j;}
max2=max(dis1[max_id]-dis1[zhongdian],dis1[zhongdian]);
tmp_ans=max(tmp_ans,max1+max2+len);
ans=min(ans,tmp_ans);
}
printf("Case %d: %d\n",g,ans);
}
return 0;
}