• BZOJ1509_NOI 2003_逃学的小孩 两次遍历 树形DP


    省赛快到了,打算练熟一下树形DP。。看的学长介绍的论文上的题(好难啊orz

    整理了很久的思路,结合别人的博客才有一点看见答案的感觉

    以点1为根

    第一遍DFS,记录每个点其儿子到它的距离最大值和次大值,并且记录来源。

    第二遍DFS,考虑当前的点X为汇聚点, -(  这样图中间那个点

    要求到x点的三个最远点,分别为x的子树到x的最大值和次大值,剩下一个点在x的父节点为根的树取

    (如果来源不是x取最大,否则取次大)

    三个最值排序后记为a,b,c,ans=max(ans,a+2*b+c)

    原文:http://3y.uu456.com/bp_5x3ew02tj60a6ri16zrz_1.html

    下面还有另外一条树形DP,记得要看。。

    ------------------------------------------------------------------------------------------

    参考另一篇博客:http://blog.csdn.net/qpswwww/article/details/46859293

    得知结论min(d(x,z),d(y,z))+d(x,y)最大时,x-y必定是树的最大直径

    这样就可以通过枚举z的位置来求

    不错的论文补充:http://blog.csdn.net/gauss_acm/article/details/40625147

    参考代码:(原文http://blog.csdn.net/cynthia_wjyi/article/details/50381405

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int maxn=200005;
    
    struct Node{
        int to,next,w;
    }e[maxn<<1];
    int tot,head[maxn],n,m;
    ll mx1[maxn],mx2[maxn],mx3[maxn],f[maxn],ans;
    bool vis[maxn];
    
    void add(int u,int v,int w){
        e[++tot]=(Node){v,head[u],w};head[u]=tot;//边从1开始命名,head[u]:以u开头的边的最后一条的编号
    }
    
    void dfs(int x){		//每个点保存子链过来的三个最长的距离(存至多三条子链,不满算0
        vis[x]=1;mx1[x]=mx2[x]=0;
        for(int i=head[x];i;i=e[i].next)if(!vis[e[i].to]){
              dfs(e[i].to);
              mx3[x]=max(mx3[x],mx1[e[i].to]+e[i].w);
              if(mx3[x]>mx2[x])swap(mx3[x],mx2[x]);
              if(mx2[x]>mx1[x])swap(mx1[x],mx2[x]);
        }
    }
    
    void dfs1(int x){
        vis[x]=1;
        for(int i=head[x];i;i=e[i].next)			//枚举x节点的子链,更新孩子父链的长度
          if(!vis[e[i].to]){
            f[e[i].to]=f[x]+e[i].w;					//继承从根节点来的链长(因为之前是算的三条子链
            if(mx1[e[i].to]+e[i].w==mx1[x])			//父节点最长链和子节点同向,就要用父节点的第二长链
              f[e[i].to]=max(f[e[i].to],mx2[x]+e[i].w);
            else
              f[e[i].to]=max(f[e[i].to],mx1[x]+e[i].w);
            dfs1(e[i].to);
          }
    }
    
    void update(ll &x,ll &y,ll &z){
        if(y>x)swap(x,y);
        if(z>x)swap(x,z);
        if(z>y)swap(y,z);
        ans=max(ans,x+(y<<1)+z);
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        int u,v,w;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);add(v,u,w);
        }
        memset(vis,0,sizeof(vis));
        dfs(1);
        memset(vis,0,sizeof(vis));
        dfs1(1);
        ans=0;
        for(int i=1;i<=n;i++)	
          f[i]<=mx3[i]?update(mx1[i],mx2[i],mx3[i]):update(mx1[i],mx2[i],f[i]);
        printf("%lld
    ",ans);
        return 0;
    } 


  • 相关阅读:
    开发人员的幽默
    SpaceBuilder 1.0RC源代码提供下载
    什么是Alpha,Beta,RC,RTM版
    SQLite数据库参数化编程时,采用命名参数的方式
    ASP.NET第四天数据库知识
    ASP.NET第五天数据库知识
    ASP.NET第五天HTML基础
    ASP.NET第二天HTML基础
    ASP.NET第四天HTML基础
    ASP.NET第一天HTML基础
  • 原文地址:https://www.cnblogs.com/Drenight/p/8611328.html
Copyright © 2020-2023  润新知