题目链接: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求直径的代码:
#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