• 洛谷 P4408 [NOI2003]逃学的小孩(树的直径)


    题目链接:https://www.luogu.com.cn/problem/P4408

    一道关于树的直径的题。

    首先明确树的直径的概念:树中所有最短路径距离的最大值。

    然后明确用DFS/BFS求树的直径的做法:先从任意一点P出发,找离它最远的点Q,再从点Q出发,找离它最远的点W,W到Q的距离就是树的直径。

       用反证法对于树的直径的证明:https://blog.csdn.net/forever_dreams/article/details/81051578

    那么这道题其实就是一道无根树上树的直径的问题:

    如图,首先根据上面的做法,用两次BFS求出树的直径,即AB。

    那么其实发现在实际上,问题要求max{AB+BC}(BC<AC)或max{AB+AC}(AC<BC),那么这两个式子可以合并成求max{AB+min{BC,AC}}。

    只要确定了直径的端点A、B,然后再枚举C点,求得最大值即为答案。

    AC代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<queue>
     5 using namespace std;
     6 typedef long long ll;
     7 const int maxn=200005; 
     8 struct node{
     9     ll to,next,val;
    10 }edge[maxn<<1];
    11 ll d[maxn],k[maxn],head[maxn],vis[maxn];
    12 int n,m,tot;
    13 queue<int> q;
    14 void add(int u,int v,int w){
    15     edge[tot].to=v;
    16     edge[tot].next=head[u];
    17     edge[tot].val=w;
    18     head[u]=tot++;
    19 }
    20 int BFS(int s){
    21     ll maxd=0,Max;
    22     memset(d,0,sizeof(d));
    23     memset(vis,0,sizeof(vis));
    24     while(!q.empty()) q.pop();
    25     q.push(s); vis[s]=1;
    26     while(!q.empty()){
    27         int u=q.front(),v; q.pop();
    28         for(int i=head[u];i!=-1;i=edge[i].next){
    29             if(vis[v=edge[i].to]) continue;
    30             vis[v]=1;
    31             d[v]=d[u]+edge[i].val;
    32             q.push(v);
    33             if(d[v]>maxd){
    34                 maxd=d[v];
    35                 Max=v;
    36             }
    37         }
    38     }
    39     return Max;
    40 }
    41 int main(){
    42     memset(head,-1,sizeof(head));
    43     scanf("%d%d",&n,&m);
    44     for(int i=1;i<=m;i++){
    45         ll x,y,z;
    46         scanf("%lld%lld%lld",&x,&y,&z);
    47         add(x,y,z); add(y,x,z);
    48     }
    49     int l=BFS(1);//A 
    50     int r=BFS(l);//B
    51     ll ans=d[r];//直径长度 
    52     for(int i=1;i<=n;i++) k[i]=d[i];//k:AC长度 
    53     BFS(r);
    54     ll M=0;
    55     for(int i=1;i<=n;i++) M=max(M,min(d[i],k[i]));//枚举C点 d:BC长度 
    56     printf("%lld
    ",ans+M);
    57     return 0;
    58 }
    59 //树的直径:从任意一点出发,找一个离它最远的点,再从这个点找离它最远的点,这便是树的直径。 
    AC代码
  • 相关阅读:
    c#+oracle存储过程实现分页
    C#中调用Matlab程序
    Oracle 自定义TYPE 的几种用法(转)
    oracle嵌套表示例
    矩阵的秩及矩阵的广义逆
    矩阵的定义及其运算规则
    矩阵微分
    matlab中取模(mod)与取余(rem)的区别
    hog源码分析
    矩阵的转置、求逆及分块
  • 原文地址:https://www.cnblogs.com/New-ljx/p/12577741.html
Copyright © 2020-2023  润新知