题目大意:给定一棵树,对树中每一个结点,求其距其他结点的最远距离。
分析:最初的想法是对每个结点求一次DFS,那样的话复杂度是O(N2),由于n最大可达10000,所以这个方法肯定会超时。根据树的特殊性可知,每个结点到距其最远的结点,要么通过其儿子结点到达,要么通过其父结点到达,由此想到可用树形动态规划。具体实现时,定义状态df[k],d1[k],d2[k],分别表示结点k通过父结点能到达的最远距离,通过儿子结点能到达的最远距离,通过儿子结点能到达的第二远距离。
1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 #define MAX(a,b) ((a)>(b)?(a):(b)) 5 #define N 10000 6 using namespace std; 7 vector<int> dep[N]; 8 int p[N],d[N],len[N],d1[N],d2[N],df[N],n,dmax; 9 void dp() 10 { 11 int i,j,u,v,tmp; 12 memset(d1,0,sizeof(d1)); 13 memset(d2,0,sizeof(d2)); 14 for(i=dmax;i>=0;i--) 15 { 16 for(j=0;j<dep[i].size();j++) 17 { 18 v=dep[i][j]; 19 if(i) 20 { 21 u=p[v]; 22 tmp=len[v]-len[u]+d1[v]; 23 if(tmp>=d1[u]) d2[u]=d1[u],d1[u]=tmp; 24 else if(tmp>=d2[u]) d2[u]=tmp; 25 } 26 } 27 } 28 } 29 int dfs(int v) 30 { 31 int u,dd; 32 u=p[v]; 33 if(u==-1) return df[v]=0; 34 if(df[v]!=-1) return df[v]; 35 dd=len[v]-len[u]; 36 if(dd+d1[v]==d1[u]) return df[v]=MAX(df[u]+dd,d2[u]+dd); 37 else return df[v]=MAX(df[u]+dd,d1[u]+dd); 38 } 39 int main() 40 { 41 int i,j,k; 42 while(~scanf("%d",&n)) 43 { 44 for(i=0;i<n;i++) dep[i].clear(); 45 p[0]=-1; 46 len[0]=dmax=0; 47 for(i=1;i<n;i++) 48 { 49 scanf("%d%d",&j,&k); 50 p[i]=j-1; 51 len[i]=len[j-1]+k; 52 d[i]=d[j-1]+1; 53 dmax=MAX(dmax,d[i]); 54 dep[d[i]].push_back(i); 55 } 56 dp(); 57 memset(df,-1,sizeof(df)); 58 for(i=0;i<n;i++) 59 {//printf("%d %d\n",d1[i],d2[i]); 60 dfs(i); 61 printf("%d\n",MAX(MAX(d1[i],d2[i]),df[i])); 62 } 63 } 64 return 0; 65 }