2007年NOIP提高组 树网的核

题目描述 Description

设 T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T 为树网(treenetwork),其中V, E分别表示结点与边的集合,W 表示各边长度的集合,并设T 有n个结点。
路径:树网中任何两结点a,b 都存在唯一的一条简单路径,用d(a,b)表示以a,b 为端点的路径的长度,它是该路径上各边长度之和。我们称d(a,b)为a,b 两结点间的距离。一点v到一条路径P的距离为该点与P 上的最近的结点的距离:
d(v,P)=min{d(v,u),u 为路径P 上的结点}。
树网的直径:树网中最长的路径称为树网的直径。对于给定的树网T,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。
偏心距 ECC(F):树网T 中距路径F 最远的结点到路径F 的距离,即
ECC(F ) = max{d(v, F ), v}。
任务:对于给定的树网T=(V, E,W)和非负整数s,求一个路径F,它是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过s(可以等于s),使偏心距ECC(F)最小。我们称这个路径为树网T=(V,E,W)的核(Core)。必要时,F 可以退化为某个结点。一般来说,在上
述定义下,核不一定只有一个,但最小偏心距是唯一的。

输入描述 Input Description

第1 行,两个正整数n和s,中间用一个空格隔开。其中n 为树网结点的个数,s为树网的核的长度的上界。设结点编号依次为1, 2, …, n。
从第2 行到第n行,每行给出3 个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2 与4 的边的长度为7。
所给的数据都是正确的,不必检验。

输出描述 Output Description

输出只有一个非负整数,为指定意义下的最小偏心距。

样例输入 Sample Input
【输入样例1】
5 2
1 2 5
2 3 2
2 4 4
2 5 3
【输入样例2】
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3

样例输出 Sample Output

【输出样例1】
5
【输出样例1】
5

数据范围及提示 Data Size & Hint
【限制】

40%的数据满足:5<=n<=15
70%的数据满足:5<=n<=80
100%的数据满足:5<=n<=300, 0<=s<=1000。边长度为不超过1000 的正整数。

只会 n <= 300 的打法qwq,数据加强版就跪了QAQ,先floyd处理出各点间的最短路,然后枚举树网的核的两个端点i,j(两个端点可以相等,且dist[i][j] <= s)和除两个端点外的其他点来找核(i–j)的最远节点,节点到核的距离为(dist[i][k] + dist[j][k] - dist[i][j])/2,每次枚举结果与答案取min即可。

#include<iostream>
#include<cstdio>
using namespace std;
int dist[450][450];
int n,s;
int main()
{
    scanf("%d%d",&n,&s);
    for(int i = 1 ; i <= n ; i ++)
        for(int j = i + 1 ; j <= n ; j ++)
            dist[i][j] = dist[j][i] = 214748364;
    for(int i = 1 ; i < n ; i ++)
    {
        int f,t,d;
        scanf("%d%d%d",&f,&t,&d);
        dist[f][t] = d;
        dist[t][f] = d;
    }
    for(int k = 1 ; k <= n ; k ++)
        for(int i = 1 ; i <= n ; i ++)
        {
            if(i != k)
            {
                for(int j = 1 ; j <= n ; j ++)
                if(dist[i][k] + dist[k][j] < dist[i][j])
                    dist[i][j] = dist[i][k] + dist[k][j];
            }
        }
    int ans = 214748364;
    for(int i = 1 ; i <= n ; i ++)
    {
        for(int j = i ; j <= n ; j ++)
        {
            if(dist[i][j] <= s)
            {
                int mx = 0;
                for(int k = 1 ; k <= n ; k ++)
                {
                    if(i != k && j != k)
                    {
                        if(mx < dist[i][k] + dist[j][k] - dist[i][j])
                            mx = dist[i][k] + dist[j][k] - dist[i][j];
                    }
                }
                if(mx <= ans)
                    ans = mx;
            }
        }
    }
    cout<<ans/2;
    return 0;
}

传送门 :
codevs 1167
tyvj 1920

你可能感兴趣的:(floyd)