描述
设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点。
路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和。我们称d(a, b)为a, b两结点间的距离。
D(v, P)=min{d(v, u), u为路径P上的结点}。
树网的直径:树网中最长的路径成为树网的直径。对于给定的树网T,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。
偏心距ECC(F):树网T中距路径F最远的结点到路径F的距离,即
ECC(F)=max{d(v, F),v∈V}
任务:对于给定的树网T=(V, E, W)和非负整数s,求一个路径F,他是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过s(可以等于s),使偏心距ECC(F)最小。我 们称这个路径为树网T=(V, E, W)的核(Core)。必要时,F可以退化为某个结点。一般来说,在上述定义下,核不一定只有一个,但最小偏心距是唯一的。
下面的图给出了树网的一个实例。图中,A-B与A-C是两条直径,长度均为20。点W是树网的中心,EF边的长度为5。如果指定s=11,则树网的核为路 径DEFG(也可以取为路径DEF),偏心距为8。如果指定s=0(或s=1、s=2),则树网的核为结点F,偏心距为12。
输入
包含n行:
第1行,两个正整数n和s,中间用一个空格隔开。其中n为树网结点的个数,s为树网的核的长度的上界。设结点编号以此为1,2,……,n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
所给的数据都是正确的,不必检验。
输出
只有一个非负整数,为指定意义下的最小偏心距。
样例输入
5 2
1 2 5
2 3 2
2 4 4
2 5 3
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
样例输出
5
5
提示
40%的数据满足:5<=n<=15
70%的数据满足:5<=n<=80
100%的数据满足:5<=n<=300,0<=s<=1000。边长度为不超过1000的正整数
求最小的偏心距。
算法:预处理出任意两点间的距离dist<i,j>,再找到直径。将直径上的所有点放入pst数组。
最后用两层循环分别枚举直径上的两个点求最小ecc。
设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点。
路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和。我们称d(a, b)为a, b两结点间的距离。
D(v, P)=min{d(v, u), u为路径P上的结点}。
树网的直径:树网中最长的路径成为树网的直径。对于给定的树网T,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。
偏心距ECC(F):树网T中距路径F最远的结点到路径F的距离,即
ECC(F)=max{d(v, F),v∈V}
任务:对于给定的树网T=(V, E, W)和非负整数s,求一个路径F,他是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过s(可以等于s),使偏心距ECC(F)最小。我 们称这个路径为树网T=(V, E, W)的核(Core)。必要时,F可以退化为某个结点。一般来说,在上述定义下,核不一定只有一个,但最小偏心距是唯一的。
下面的图给出了树网的一个实例。图中,A-B与A-C是两条直径,长度均为20。点W是树网的中心,EF边的长度为5。如果指定s=11,则树网的核为路 径DEFG(也可以取为路径DEF),偏心距为8。如果指定s=0(或s=1、s=2),则树网的核为结点F,偏心距为12。
输入
包含n行:
第1行,两个正整数n和s,中间用一个空格隔开。其中n为树网结点的个数,s为树网的核的长度的上界。设结点编号以此为1,2,……,n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
所给的数据都是正确的,不必检验。
输出
只有一个非负整数,为指定意义下的最小偏心距。
样例输入
5 2
1 2 5
2 3 2
2 4 4
2 5 3
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
样例输出
5
5
提示
40%的数据满足:5<=n<=15
70%的数据满足:5<=n<=80
100%的数据满足:5<=n<=300,0<=s<=1000。边长度为不超过1000的正整数
求最小的偏心距。
算法:预处理出任意两点间的距离dist<i,j>,再找到直径。将直径上的所有点放入pst数组。
最后用两层循环分别枚举直径上的两个点求最小ecc。
90分代码:
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 500
#define INF 1000007
using namespace std;
int n,s;
int net[MAXN][MAXN],dist[MAXN][MAXN],dis[MAXN];
int vis[MAXN],path[MAXN];
int pts[MAXN],sum=0;
void read(){
cin >> n >> s;
int u,v,w;
memset(net,0,sizeof net);
for (int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
net[u][v]=net[v][u]=w;
}
}
void spfa(int sc)
{
queue<int> Q;
for (int i=1; i<=n; i++) dis[i] = INF;
dis[sc] = 0;
vis[sc] = 1;
Q.push(sc);
while (!Q.empty()){
int tmp = Q.front();
for (int i=1; i<=n; i++)
{
if (net[tmp][i] && dis[tmp] + net[tmp][i] < dis[i])
{
dis[i] = dis[tmp] + net[tmp][i];
if (!vis[i])
{
Q.push(i);
vis[i] = 1;
}
}
}
Q.pop();
vis[tmp] = 0;
}
for (int i=1;i<=n;i++) dist[sc][i]=dist[i][sc]=dis[i];
}
void dfs(int u,int v,int k){
path[k]=u;
if (u==v) for (int i=1;i<=k;i++) pts[path[i]]=1;
else for (int i=1;i<=n;i++)
if (net[u][i] && !vis[i])
{
vis[i]=1;
dfs(i,v,k+1);
}
}
void init(){
read();
for (int i=1;i<=n;i++) spfa(i);//用spfa预处理出两点间距离
for (int i=1;i<=n;i++) dist[i][i]=0;
int maxv=0,u[MAXN],v[MAXN],cnt=0;
for (int i=1;i<n;i++)
for(int j=i;j<=n;j++) maxv=max(maxv,dist[i][j]);
for (int i=1;i<=n;i++)
for(int j=i;j<=n;j++) if (dist[i][j]==maxv) {u[++cnt]=i;v[cnt]=j;}
//直径可能不止一条
for (int i=1;i<=cnt;i++)
{
memset(vis,0,sizeof vis);
vis[u[i]]=1;
dfs(u[i],v[i],1);
//找直径上的所有点
}
}
bool check(int u,int v){
return pts[u]&&pts[v];
}
//判断:是否在直径上
int ecc(int u,int v){
int ECC=0;
for (int i=1;i<=n;i++) {
int d=min(dist[i][u],dist[i][v]);
ECC=max(ECC,d);
}
return ECC;
}
//计算偏心距
int main(){
//freopen("data.in","r",stdin);
init();
int ans=INF;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (check(i,j)&& dist[i][j]<=s) ans = min(ans,ecc(i,j));
cout<<ans;
return 0;
}