【描述】
Dragon同學一天撿到了一根非常非常巨大的樹枝,於是同學就想啊,如果把這根樹枝多餘的分叉剔掉最後剩下一根沒有分叉的木棍,用它自衛就沒人敢欺負我們科學家了呀:)
你的任務是,對給定樹枝,求出它包含的最長木棍。
【輸入格式】
第一行一個正整數n,表示頂點數,頂點從1至n編號。
然後n – 1行每行兩個正整數u, v表示u, v之間有一條邊,每條邊的長度為1。
保證輸入的是一棵樹。
【輸出格式】
只有一行,表示給定樹的最長鏈長度。
【範例輸入】
5
1 2
1 3
1 4
1 5
【範例輸出】
2
【分析】
很明顯,求樹中的最長鏈。設f[i]是i的子樹中最遠的點到自己的距離,p[i]是第二遠的點到自己的距離。那麼所有的點鐘最大的f[i]+p[i]就是答案。
第一次寫——臨邊表。顯然存不下。
第二次寫——類比鏈表。用的遞迴造樹,爆掉。
想到了要用手工的棧。
可是我不知道怎麼寫囧。
於是看了標程。
原來還可以這麼構樹!!!
原來手工棧這麼寫!!!
頓悟。
第三次——AC。
#include <stdio.h>#include <stdlib.h>#define maxn 1000010int f[maxn];int father[maxn],str[maxn];struct ss{ int num,next;} a[maxn];int tot,n,u,v,p,ans;int c[maxn],deep[maxn],sta[maxn],top,e[maxn],te;void ins(int x,int y){ a[++tot].num=y; a[tot].next=str[x]; str[x]=tot;}int cmp(const void*a,const void*b){ int c=*(int*)a,d=*(int*)b; if (deep[c]<deep[d]) return -1; if (deep[c]>deep[d]) return 1; return 0;}int main(){ freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d",&n); for (int i=1;i<n;++i) { scanf("%d%d",&u,&v); ins(u,v); ins(v,u); } sta[0]=1; e[0]=str[1]; father[1]=0; while (top>=0) { te=e[top]; if (!te) --top; else { v=sta[top]; u=a[te].num; e[top]=a[te].next; if (u!=father[v]) { sta[++top]=u; e[top]=str[u]; deep[u]=deep[v]+1; father[u]=v; } } } for (int i=1;i<=n;++i) c[i]=i; deep[0]=-1; qsort(c,n+1,sizeof(int),cmp); for (int i=n;i>0;--i) { u=c[i]; te=str[u]; if (!te) continue; p=0; do { v=a[te].num; if (father[u]!=v) if (f[v]+1>f[u]) { p=f[u]; f[u]=f[v]+1; } else if (f[v]+1>p) p=f[v]+1; te=a[te].next; } while (te); if (f[u]+p>ans) ans=f[u]+p; } printf("%d\n",ans); return 0;}