题目在这里呀~
给你一棵树,改变一条边使得树的直径最小,求最小直径。
这题在考试的题目有加强版然而暴力都没有写完qaq所以找到了这道题。
这题还是挺友善的嗷(Case x忘记写了也是很迷了
枚举删除哪一条边,把树分成了两棵树,然后加的那条边一定是两棵树中心的连线。(一棵树的中心到其他节点最深的深度最小)所以只要用树形DP求中心即可。最后整棵树的直径是两棵树的直径以及两棵树中心到其他节点的对应深度加上边的长度。
//Suplex
#include
#include
#include
#include
#include
#define N 3000
using namespace std;
const int inf=1e9;
int hxy,T,n,cnt,ans1,ans2,ans,p1,p2,max1,max2,vet[N+N],Next[N+N],head[N],len[N+N];
int d1[N],d2[N],c1[N],g[N],f[N],vis[N];
struct edge{
int u,v,l;
}e[N+N];
inline void add_edge(int u,int v,int l)
{
vet[++cnt]=v;Next[cnt]=head[u];len[cnt]=l;head[u]=cnt;
}
void dfs1(int u,int fa)
{
vis[u]=1;
for(int i=head[u];i!=-1;i=Next[i]){
int v=vet[i];
if(v==fa) continue;
dfs1(v,u);
if(d1[v]+len[i] > d1[u]){
d2[u]=d1[u];
d1[u]=d1[v]+len[i];
c1[u]=v;
}else if(d1[v]+len[i] > d2[u]) d2[u]=d1[v]+len[i];
}
}
void dfs2(int u,int fa)
{
for(int i=head[u];i!=-1;i=Next[i]){
int v=vet[i];
if(v==fa) continue;
if(v==c1[u]) g[v]=max(g[u],d2[u])+len[i];
else g[v]=max(g[u],d1[u])+len[i];
dfs2(v,u);
}
}
int main()
{
scanf("%d",&T);
while(T--){
hxy++;
scanf("%d",&n);
for(int i=1;i<n;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].l);
ans=inf;
for(int i=1;i<n;i++){
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
memset(c1,0,sizeof(c1));
memset(g,0,sizeof(g));
memset(f,0,sizeof(f));
memset(head,-1,sizeof(head));
cnt=0;ans1=inf;ans2=inf;max1=0;max2=0;
for(int j=1;j<n;j++)
if(i!=j) add_edge(e[j].u,e[j].v,e[j].l),add_edge(e[j].v,e[j].u,e[j].l);
memset(vis,0,sizeof(vis));
dfs1(e[i].u,-1);
dfs2(e[i].u,-1);
for(int j=0;j<n;j++)
if(vis[j]) f[j]=max(g[j],d1[j]);
for(int j=0;j<n;j++)
if(vis[j])
if(f[j]<ans1){ans1=f[j];p1=j;}
for(int j=0;j<n;j++)
if(vis[j]) max1=max(max1,max(g[j],d2[j])+d1[j]);
memset(vis,0,sizeof(vis));
dfs1(e[i].v,-1);
dfs2(e[i].v,-1);
for(int j=0;j<n;j++)
if(vis[j]) f[j]=max(d1[j],g[j]);
for(int j=0;j<n;j++)
if(vis[j])
if(f[j]<ans2){ans2=f[j];p2=j;}
for(int j=0;j<n;j++)
if(vis[j]) max2=max(max2,max(g[j],d2[j])+d1[j]);
ans=min(ans,max(max(max1,max2),ans1+ans2+e[i].l));
}
printf("Case %d: %d\n",hxy,ans);
}
return 0;
}