hdu 3534 树形dp ***

题意:统计一棵带权树上两点之间的最长距离以及最长距离的数目

链接:点我

首先统计出结点到叶子结点的最长距离和次长距离。

然后找寻经过这个点的,在这个为根结点的子树中的最长路径个数目。

  1 #include <string.h>

  2 #include <iostream>

  3 #include <algorithm>

  4 #include <stdio.h>

  5 using namespace std;

  6 const int MAXN=100010;

  7 const int INF=0x3f3f3f3f;

  8 struct Node

  9 {

 10     int to,next,len;

 11 }edge[MAXN*2];

 12 int head[MAXN];

 13 int tol;

 14 int maxn[MAXN];//该节点往下到叶子结点的最大距离

 15 int smaxn[MAXN];// 次大距离

 16 int maxn_num[MAXN];//最大距离的个数

 17 int smaxn_num[MAXN];//次大距离的个数

 18 int path[MAXN];//该结点为根的子树中,包含该结点的最长路径长度

 19 int num[MAXN];//最长路径的长度

 20 

 21 void init()

 22 {

 23     tol=0;

 24     memset(head,-1,sizeof(head));

 25 }

 26 void add(int u,int v,int w)

 27 {

 28     edge[tol].to=v;

 29     edge[tol].len=w;

 30     edge[tol].next=head[u];

 31     head[u]=tol++;

 32     edge[tol].to=u;

 33     edge[tol].len=w;

 34     edge[tol].next=head[v];

 35     head[v]=tol++;

 36 }

 37 

 38 void dfs(int u,int pre)

 39 {

 40     maxn[u]=smaxn[u]=0;

 41     maxn_num[u]=smaxn_num[u]=0;

 42     for(int i=head[u];i!=-1;i=edge[i].next)

 43     {

 44         int v=edge[i].to;

 45         if(v==pre)continue;

 46         dfs(v,u);

 47         if(maxn[v]+edge[i].len>maxn[u])

 48         {

 49             smaxn[u]=maxn[u];

 50             smaxn_num[u]=maxn_num[u];

 51             maxn[u]=maxn[v]+edge[i].len;

 52             maxn_num[u]=maxn_num[v];

 53         }

 54         else if(maxn[v]+edge[i].len==maxn[u])

 55         {

 56             maxn_num[u]+=maxn_num[v];

 57         }

 58         else if(maxn[v]+edge[i].len>smaxn[u])

 59         {

 60             smaxn[u]=maxn[v]+edge[i].len;

 61             smaxn_num[u]=maxn_num[v];

 62         }

 63         else if(maxn[v]+edge[i].len==smaxn[u])

 64         {

 65             smaxn_num[u]+=maxn_num[v];

 66         }

 67     }

 68     if(maxn_num[u]==0)//叶子结点

 69     {

 70         maxn[u]=smaxn[u]=0;

 71         maxn_num[u]=smaxn_num[u]=1;

 72         path[u]=0;

 73         num[u]=1;

 74         return;

 75     }

 76     //到这里已经统计出了u节点到叶子的最长和次长

 77     int c1=0,c2=0;

 78     for(int i=head[u];i!=-1;i=edge[i].next)

 79     {

 80         int v=edge[i].to;

 81         if(v==pre)continue;

 82         if(maxn[u]==maxn[v]+edge[i].len)c1++;

 83         else if(smaxn[u]==maxn[v]+edge[i].len)c2++;

 84     }

 85     path[u]=0;

 86     num[u]=0;

 87     if(c1>=2)//最长+最长

 88     {

 89         int tmp=0;

 90         path[u]=maxn[u]*2;

 91         for(int i=head[u];i!=-1;i=edge[i].next)

 92         {

 93             int v=edge[i].to;

 94             if(v==pre)continue;

 95             if(maxn[u]==maxn[v]+edge[i].len)

 96             {

 97                 num[u]+=tmp*maxn_num[v];

 98                 tmp+=maxn_num[v];

 99             }

100         }

101     }

102     else if(c1>=1 && c2>=1)//最长+次长

103     {

104         path[u]=maxn[u]+smaxn[u];

105         for(int i=head[u];i!=-1;i=edge[i].next)

106         {

107             int v=edge[i].to;

108             if(v==pre)continue;

109             if(maxn[u]==maxn[v]+edge[i].len)

110             {

111                 num[u]+=maxn_num[v]*smaxn_num[u];

112             }

113         }

114     }

115     else//最长

116     {

117         path[u]=maxn[u];

118         num[u]=maxn_num[u];

119     }

120 }

121 int main()

122 {

123     int n;

124     while(scanf("%d",&n)==1)

125     {

126         int u,v,w;

127         init();

128         for(int i=1;i<n;i++)

129         {

130             scanf("%d%d%d",&u,&v,&w);

131             add(u,v,w);

132         }

133         dfs(1,-1);

134         int ans1=0,ans2=0;

135         for(int i=1;i<=n;i++)

136         {

137             if(path[i]>ans1)

138             {

139                 ans1=path[i];

140                 ans2=num[i];

141             }

142             else if(path[i]==ans1)

143                 ans2+=num[i];

144         }

145         printf("%d %d\n",ans1,ans2);

146     }

147     return 0;

148 }

 

你可能感兴趣的:(HDU)