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;
}


 
原文地址:https://www.cnblogs.com/GMSD/p/11282273.html