1. 程式人生 > >用bfs求dfs序(先序遍歷序)

用bfs求dfs序(先序遍歷序)

給你一棵樹
求這棵樹的dfs序
但是樹的深度會爆系統棧
那麼如何求出dfs序?
當然,空間足夠
一般情況下有兩種做法
1. 手寫棧跑dfs
2. 跑bfs
第一種太過簡單
我不予簡介
我們主要說第二種
首先我們知道dfs序就是要先遍歷左子樹
那麼我們是不是可以用一種神奇的方法
在bfs序的基礎上做出dfs序
首先
我們知道
無論是dfs序還是bfs序
根節點一定在第一個位置
同時bfs序可得出一個分層結構
正序遍歷bfs序到當前點時,當前點的父親一定被遍歷過
那麼我們可以這樣考慮
是否可以通過父親的位置來求出當前點的位置?
答案是肯定的啊
dfs序中同一深度的兒子順序和bfs序中相同
同一父親的不同兒子在dfs序中位置值相差的數值
是以兩兒子中較左兒子為根的子樹的節點的數量
那麼我們就可以在bfs時維護一個size
然後遍歷bfs序
維護一個last表示從上一個點推得的這一點應在的位置
如果當前點和前一個點父親不同
那麼last為當前點父親的位置+1
如果當前點和前一個點父親相同
那麼last+=前一個點的size
遍歷後就求出了dfs序!
程式碼如下

#include <cstdio>
#include <cstdlib>
#include <cctype>
char getc()
{
    static const int LEN = 1<<15;
    static char buf[LEN],*S=buf,*T=buf;
    if(S == T)
    {
        T = (S=buf)+fread(buf,1,LEN,stdin);
        if(S == T)return EOF;
    }
    return *S++;
}
int read()
{
    static char ch;
    static int
D; while(!isdigit(ch=getc())); for(D=ch-'0'; isdigit(ch=getc());) D=(D<<3)+(D<<1)+(ch-'0'); return D; } int n,idx; int to[2000000],next[2000000],head[1000001], q[1000001],fa[1000001],size[1000001], dfs[1000001],zz[1000001]; void add(int x,int y) { to[++idx]=y; next[idx]=head[x]; head[x]=idx; to[++idx]=x
; next[idx]=head[y]; head[y]=idx; return ; } void bfs() { int l=0,r=0; q[r++]=1; while(l!=r) { int x=q[l++]; size[x]=1; for(int i=head[x];i;i=next[i]) if(to[i]!=fa[x]) { fa[to[i]]=x; q[r++]=to[i]; } } for(int i=n-1;i>=0;--i) size[fa[q[i]]]+=size[q[i]]; return ; } int main() { n=read(); for(int i=1;i<n;++i) { int a=read(),b=read(); add(a,b); } bfs(); dfs[1]=1; zz[1]=2; int last; for(int i=1;i<n;++i) { if(fa[q[i]]!=fa[q[i-1]]) last=zz[fa[q[i]]]; else (last+=size[q[i-1]]); dfs[last]=q[i]; zz[q[i]]=last+1; } for(int i=1;i<=n;++i) printf("%d\n",dfs[i]); return 0; }