zoukankan      html  css  js  c++  java
  • 树网的核-Floyd+宽搜

    题目:

    VIJOS-P1362 树网的核

    Time Limit: 1 Sec  Memory Limit: 128 MB

    Description

    设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 2
    1 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
    ",ans,point[i],point[j]);
            }        
        }
        printf("%d",ans);
    }
       
     
  • 相关阅读:
    ExcelHelper
    c# 文件的读写
    Wav文件操作类
    c# & (与) 、^ (异或)和 >>(<<位移运算)
    c# 高精度的timer
    c# 生成txt文件,写入内容
    C# 对 list<T>中的数据按某字段的大小进行排序
    OC 底层探索 06、 isa 2个经典问题分析
    OC 底层探索 05、属性、成员、实例变量简析
    数据结构与算法 0、 汇总简介
  • 原文地址:https://www.cnblogs.com/Marcelo/p/13491064.html
Copyright © 2011-2022 走看看