题目:
VIJOS-P1362 树网的核
Time Limit: 1 Sec Memory Limit: 128 MBDescription
设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。Input
包含n行: 第1行,两个正整数n和s,中间用一个空格隔开。其中n为树网结点的个数,s为树网的核的长度的上界。设结点编号以此为1,2,……,n。 从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。 所给的数据都是正确的,不必检验。Output
只有一个非负整数,为指定意义下的最小偏心距。Sample Input
5 21 2 5
2 3 2
2 4 4
2 5 3
Sample Output
5 分析: 结论:选取任意直径答案都相同 证:设其交点为N,则两侧的每条直径权值和相等 所以仅处理一条直径即可 N^3做法:Floyd+宽搜 1.建图,并Floyd 2.找出直径,并记录直径上的点 3.枚举直径上的起点和终点,并求出偏心距 偏心距求法: 偏心距可能出现在三个位置:1.直径起点到枚举起点的距离 2.直径终点到枚举终点的距离 3.枚举的路段中其他的分支 前两个都已用Floyd算法得出,第三个分别在每个点上进行宽搜(注意,不能搜到直径上的点) 注意:1.宽搜的初始化 2.拷贝f数组避免将其污染 代码如下#include<stdio.h> #include<queue> #include<cstring> using namespace std; queue<int>q; #define N 301 #define inf 10000001 int f[N][N]; int f1[N][N]; int dis[N]; int qu[N]; int node[N][N]; int end[N]; int point[N]; int vis[N]; int cnt=1; int n,s; int max(int x,int y) { return x>y?x:y; } int min(int x,int y) { return x<y?x:y; } int bfs(int x,int cnt) { memset(vis,0,sizeof(vis)); for(int i=1;i<=cnt;i++) vis[point[i]]=1; q.push(x); vis[x]=1; int re=0; while(!q.empty()) { int imp=q.front(); q.pop(); for(int i=1;i<=n;i++) { if(vis[i]==0&&f1[i][imp]!=inf) { dis[i]=dis[imp]+f1[i][imp]; re=max(dis[i],re); q.push(i); vis[i]=1; } } } return re; } int main() { scanf("%d%d",&n,&s); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) if(i!=j) f1[i][j]=f[i][j]=inf; } for(int i=1;i<n;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); f1[x][y]=f[x][y]=z; f1[y][x]=f[y][x]=z; } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { f[i][j]=min(f[i][j],f[i][k]+f[k][j]); } } } int d=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { d=max(d,f[i][j]); } } for(int i=1;i<=n;i++) { for(int j=i;j<=n;j++) { if(f[i][j]==d) end[1]=i,end[2]=j; } } int ans=inf; for(int k=1;k<=n;k++) { if(f[end[1]][end[2]]==f[end[1]][k]+f[k][end[2]]&&k!=end[1]&&k!=end[2]) point[++cnt]=k; } point[1]=end[1]; point[++cnt]=end[2]; for(int i=1;i<=n;i++) dis[i]=bfs(i,cnt); for(int i=1;i<=cnt;i++) { int p=dis[point[i]]; for(int j=i;j<=cnt;j++) { if(f[point[i]][point[j]]>s) continue; if(p<dis[point[j]]) p=dis[point[j]]; int sr=max(f[point[i]][end[1]],f[point[j]][end[2]]); sr=max(sr,p); if(sr==0) continue; ans=min(sr,ans); // printf("%d p:%d %d\n",ans,point[i],point[j]); } } printf("%d",ans); }