題意:給你一顆n個節點n-1條邊的樹,每條邊都有一個權值,現在讓你任意移動一條邊然後把這條邊串連到任意兩個點上,最後問你怎樣移動才能使樹上相距最遠的兩個點距離最小。
思路:先求出樹的最長路,然後枚舉移動最長路上的所有邊,移走這條邊後,原樹必定分為不串連的兩顆子樹,分別求這兩顆子樹的最長路,然後分別找到兩顆子樹最長路上靠近中點的點,那麼最長路有三種情況:假設這條邊為 u -> v
1.u的左子樹的直徑;
2.v的右子樹的直徑;
3.u的左子樹的直徑上中點分割的最長路徑 + v的右子樹的直徑上中點分割的最長路徑 + 邊權
每枚舉一條邊,就取這三種情況的最大值;
需要注意的事:兩棵子樹的最長路,一定是以整棵樹的最長路的兩個端點為起始點的,因此只需要預先處理出所有點到兩個端點的距離,然後根據刪除的最長路邊求兩顆子樹中的最大值即可。
所以我們只需2次BFS就夠了;
我感覺My Code很簡短:
#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;#define N 3000int 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;}