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\n",ans);
    return 0;
} 


posted @ 2017-04-23 00:55  Drenight  阅读(137)  评论(0编辑  收藏  举报