3721 Building Roads
Time Limit:16000/8000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)Description###
There is a magic planet in the space. There is a magical country on the planet. There are N cities in the country. The country is magical because there are exactly N-1 magic roads between the N cities, and from each city, it is possible to visit any other city. But after the huge expansion of the country, the road system seems to be messy. The moderator decided to rebuild the road system.
As a worker, I cannot do too much things. I could just move one road to another position connecting arbitrary 2 cities using my magic, keeping its length unchanged. Of course, afterwards all the N cities have to be still connected. I wonder how to move in order to make the farthest distance between any two cities minimum. Could you solve it for me?
Input###
The first line of the input is one integer T (T ≤ 10), and then T test cases follow.
Each test case begins with a line contains only one integer N (N ≤ 2500), means there are N magic cities. The cities are numbered from 0 to N-1.
Following N-1 lines, each line has 3 integers a, b and c, means there is a magic road between a and b with distance c. (0 <= a, b < N, 0 < c <= 1000)
Output###
For each test case, output the case number and the corresponding minimum >farthest distance. See sample for detailed format.
Sample Input 1###
4
0 1 2
1 2 2
2 3 2
5
0 1 1
1 2 2
2 3 3
3 4 4
Sample Output 1###
Case 1: 4
Case 2: 7HINT###
题目地址: HDU 3721 Building Roads
题解:
题目大意:一棵树断掉一条边,用此边再连接两个点,使得还是一棵树,且使任意两个点之间的最远距离最小,求此距离
要求即为直径最小
枚举断边,分成两棵树,连边的两个端点分别在两棵树上,考虑连哪两个点
树的中心:这个点到树的其他结点的最远距离最近
显然就是连两棵树的中心了,那么如何求树的中心
d1[u]表示以u为根的子树中,u到叶子结点距离的最大值,用s1[u]记录该叶子结点
d2[u]表示以u为根的子树中,u到叶子结点距离的次大值
up[u]表示树中除了以u为根的子树中的叶子结点外,其他的叶子结点到u的最大值
这些都非常好求
树的中心即为T[u]=max(d1[u],up[u])最小的点
两棵树合并后的直径有三种情况:树1的直径,树2的直径,两个中心的T[u]相加+删掉边的长度
www.cnblogs.com/AGFghy/
AC代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,Q,num,d,ans1,ans2,ans;
int head[3005],Next[6005],point[6005],len[6005];
int a[5],u[3005],v[3005],l[3005],up[3005],d1[3005],d2[3005],s1[3005],belong[3005];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
inline void add(int u,int v,int l)
{
point[++num]=v;
len[num]=l;
Next[num]=head[u];
head[u]=num;
}
void dfs1(int now,int pre,int kd)
{
belong[now]=1-kd;
for (int i=head[now]; i; i=Next[i])
{
int v=point[i];
if (v==pre||v==a[kd]) continue;
dfs1(v,now,kd);
if (d1[now]<d1[v]+len[i])
{
d2[now]=d1[now];
d1[now]=d1[v]+len[i]; s1[now]=v;
}
else
if (d2[now]<d1[v]+len[i]) d2[now]=d1[v]+len[i];
}
}
void dfs2(int now,int pre,int kd)
{
for (int i=head[now]; i; i=Next[i])
{
int v=point[i];
if (v==pre||v==a[kd]) continue;
if (v!=s1[now]) up[v]=max(up[now],d1[now])+len[i];
else up[v]=max(up[now],d2[now])+len[i];
dfs2(v,now,kd);
}
}
int main()
{
Q=read();
for (int cas=1; cas<=Q; cas++)
{
n=read();
num=0;
for (int i=1; i<=n; i++)
head[i]=0;
for (int i=1; i<=n-1; i++)
{
u[i]=read()+1; v[i]=read()+1; l[i]=read();
add(u[i],v[i],l[i]); add(v[i],u[i],l[i]);
}
ans=1e9;
for (int i=1; i<=n-1; i++)
{
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
memset(up,0,sizeof(up));
a[0]=u[i]; a[1]=v[i];
dfs1(a[0],0,1); dfs2(a[0],0,1);
dfs1(a[1],0,0); dfs2(a[1],0,0);
d=0; ans1=ans2=1e9;
for (int j=1; j<=n; j++)
d=max(d,d1[j]+d2[j]);
for (int j=1; j<=n; j++)
if (belong[j]==0) ans1=min(ans1,max(up[j],d1[j]));
else ans2=min(ans2,max(up[j],d1[j]));
ans=min(ans,max(d,ans1+ans2+l[i]));
}
printf("Case %d: %d
",cas,ans);
}
return 0;
}