• P4408 [NOI2003]逃学的小孩


    题目描述

    Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:“喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?”一听说要考试,Chris的父母就心急如焚,他们决定在尽量短的时间内找到Chris。他们告诉Chris的老师:“根据以往的经验,Chris现在必然躲在朋友Shermie或Yashiro家里偷玩《拳皇》游戏。现在,我们就从家出发去找Chris,一但找到,我们立刻给您打电话。”说完砰的一声把电话挂了。

    Chris居住的城市由N个居住点和若干条连接居住点的双向街道组成,经过街道x需花费Tx分钟。可以保证,任两个居住点间有且仅有一条通路。Chris家在点C,Shermie和Yashiro分别住在点A和点B。Chris的老师和Chris的父母都有城市地图,但Chris的父母知道点A、B、C的具体位置而Chris的老师不知。

    为了尽快找到Chris,Chris的父母会遵守以下两条规则:

    1. 如果A距离C比B距离C近,那么Chris的父母先去Shermie家寻找Chris,如果找不到,Chris的父母再去Yashiro家;反之亦然。
    2. Chris的父母总沿着两点间唯一的通路行走。

    显然,Chris的老师知道Chris的父母在寻找Chris的过程中会遵守以上两条规则,但由于他并不知道A,B,C的具体位置,所以现在他希望你告诉他,最坏情况下Chris的父母要耗费多长时间才能找到Chris?

    输入格式

    输入文件第一行是两个整数N(3 ≤ N ≤ 200000)和M,分别表示居住点总数和街道总数。

    以下M行,每行给出一条街道的信息。第i+1行包含整数Ui、Vi、Ti(1≤Ui, Vi ≤ N,1 ≤ Ti ≤ 1000000000),表示街道i连接居住点Ui和Vi,并且经过街道i需花费Ti分钟。街道信息不会重复给出。

    输出格式

    输出文件仅包含整数T,即最坏情况下Chris的父母需要花费T分钟才能找到Chris。

    输入输出样例

    输入 #1
    4 3
    1 2 1
    2 3 1
    3 4 1
    输出 #1
    4

    吐槽一下:题目这么长一大串,讲了一个故事,但其实用简洁的语言来说人话:在一个无根树中,有三个点ABC,求AB+BC(假设AB<AC)的最大值
    ———————————————————————————————————————————————————————————————
    那不就是先求树的直径吗(直径:在一个树中相距最远的两个点之间的长度),设B,C点为直径的两个端点,那么A点在这条直径上

    如图所示:四个点,三条边
    那么很容易得出直径为3 端点为1 4
    设这两个点为B C
    2 3分别设为A1,A2
    分类讨论:
    1.当点A存在于A1时
    那么顺序为A1——>B——>A1——>A2——>C
    总长度为7
    2.当点A存在于A2时
    顺序为A2——>C——>A2——>A1——>B
    总长度为9
    显然第二种情况好一些

    因此可以推出(d[j][i]表示i,j之间的最短距离):

    ans=max(min(d[Ai][B],d[Ai][C])+d[B][C]
    Ai表示存在于以BC为端点的直径上的所有点

    一次搜索求直径端点,两次搜索枚举中间的点

    上代码:
    #include<bits/stdc++.h>
    using namespace std;
    
    const long long N=200002;
    long long number,m,ver[N],next[N],head[N],tot,edge[N],res[N],ans=0;
    long long q[N],hd,tl,dis[N],maxx=-1,maxi=0,start,begin,d1[N],d2[N];
    
    long long read(){
        long long s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
        return s*w;
    }
    
    void add(long long x,long long y,long long z){
        tot++;ver[tot]=y;
        edge[tot]=z;next[tot]=head[x];
        head[x]=tot;
    }
    
    void bfs(long long x){
        memset(res,0,sizeof(res));memset(dis,0,sizeof(dis));
        hd=0;tl=1;q[1]=x;res[x]=1;
        while(hd^tl){
            hd++;
            for(long long i=head[q[hd]];i;i=next[i]){
                long long y=ver[i];
                if(!res[y]){
                    res[y]=1;tl++;q[tl]=y;
                    dis[y]=dis[q[hd]]+edge[i];
                }
            }
        }
        for(long long i=1;i<=number;i++){
            if(dis[i]>=maxx)maxx=dis[i],maxi=i;
        }
    }
    
    void dfs1(long long x,long long pd){
        for(long long i=head[x];i;i=next[i]){
            long long y=ver[i];
            if(y==pd)continue;
            d1[y]=d1[x]+edge[i];
            dfs1(y,x);
        }
    }
    
    void dfs2(long long x,long long pd){
        for(long long i=head[x];i;i=next[i]){
            long long y=ver[i];
            if(y==pd)continue;
            d2[y]=d2[x]+edge[i];
            dfs2(y,x);
        }
    }
    
    int main(){
        number=read();m=read();
        for(long long i=1;i<=m;i++){
            long long x=read(),y=read(),z=read();
            add(x,y,z);add(y,x,z);
        }
        bfs(1);
        start=maxi;bfs(maxi);
        begin=maxi;
        dfs1(start,0);dfs2(begin,0);
        for(long long i=1;i<=number;i++)ans=max(ans,min(d1[i],d2[i]));
        cout<<ans+maxx;
        return 0;
    }
    
    
    
     
  • 相关阅读:
    分类、回归问题Loss
    eclipse导入原代码打包war包的方法
    linux安装java,tomcat,mysql
    将代码部署到tomcat的方式
    记一次电脑密码重置恢复的过程win11
    java内部类与静态内部类
    Ribbon 实现客户端负载均衡与LoadBalanced注解
    公式选股 基本定义和函数, 常用例子
    How To: Use C Macros Efficiently in Your Code
    ASP.NET 将DataTable解析成JSON
  • 原文地址:https://www.cnblogs.com/GMSD/p/11282273.html
Copyright © 2020-2023  润新知