hdoj3534(树形dp,求树的直径的条数)

题目链接:https://vjudge.net/problem/HDU-3534

题意:给出一棵树,求树上最长距离(直径),以及这样的距离的条数。

思路:如果只求直径,用两次dfs即可。但是现在要求最长距离的条数,用dp1[u]记录以u为根的子树中叶子结点到u的最长距离,dp2[u]表示最长距离的条数,这两个比较容易维护。dfs过程中更新答案,用ans1表示树上直径,ans2表示该直径的条数,当dp1[v]+w+dp1[u]>ans1时更新。

AC代码:

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn=1e4+5;
typedef long long LL;
int n,cnt,head[maxn];
LL ans1,ans2,dp1[maxn],dp2[maxn];

struct node{
    int v,w,nex;
}edge[maxn<<1];

void adde(int u,int v,int w){
    edge[++cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nex=head[u];
    head[u]=cnt;
}

void dfs(int u,int fa){
    dp1[u]=0,dp2[u]=1;
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v,w=edge[i].w;
        if(v==fa) continue;
        dfs(v,u);
        int tmp=dp1[v]+w;
        if(tmp+dp1[u]>ans1){
            ans1=tmp+dp1[u];
            ans2=dp2[u]*dp2[v];
        }
        else if(tmp+dp1[u]==ans1){
            ans2+=dp2[u]*dp2[v];
        }
        if(tmp>dp1[u]){
            dp1[u]=tmp;
            dp2[u]=dp2[v];
        }
        else if(tmp==dp1[u]){
            dp2[u]+=dp2[v];
        }
    }
}

int main(){
    while(~scanf("%d",&n)){
        cnt=ans1=ans2=0;
        for(int i=1;i<=n;++i)
            head[i]=0;
        for(int i=1;i<n;++i){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            adde(u,v,w);
            adde(v,u,w);
        }
        dfs(1,0);
        printf("%lld %lld\n",ans1,ans2);
    }
    return 0;
}

 

 

顺便附上只用两次dfs求直径的代码:

hdoj3534(树形dp,求树的直径的条数)
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

typedef long long LL;
const int maxn=1e4+5;
int n,cnt,head[maxn];
LL dp1[maxn],dp2[maxn];

struct node{
    int v,w,nex;
}edge[maxn<<1];

void adde(int u,int v,int w){
    edge[++cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nex=head[u];
    head[u]=cnt;
}

void dfs(int u,int fa){
    dp1[u]=0;
    int flag=0;
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v,w=edge[i].w;
        if(v==fa) continue;
        flag=1;
        dfs(v,u);
        if(dp1[v]+w>dp1[u]){
            dp1[u]=dp1[v]+w;
            dp2[u]=dp2[v];
        }
    }
    if(!flag) dp2[u]=u;
}

int main(){
    while(~scanf("%d",&n)){
        cnt=0;
        for(int i=1;i<=n;++i)
            head[i]=0;
        for(int i=1;i<n;++i){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            adde(u,v,w);
            adde(v,u,w);
        }
        dfs(1,0);
        int tmp=dp2[1];
        dfs(tmp,0);
        printf("%lld\n",dp1[tmp]);
    }
    return 0;
}
View Code

 

上一篇:洛谷 P1880 [NOI1995]石子合并(区间DP)


下一篇:2019南京网络赛 D. Robots (概率dp)