樹的遍歷——DFS與BFS


posted on 2019-08-28 16:45:21

A.樹的遍歷

題目描述

給定一棵 \(n\) 個節點的無根樹(節點編號 \(0\)\(n-1\))和一個節點\(x\),請以 \(x\) 號節點為根,做一次 DFS 與一次 BFS

輸入格式

從標准輸入讀入數據。

第一行輸入一個正整數 \(n\)\(1 \leq n \leq 200000\)),代表這棵樹的節點數目。

接下來 $ n-1 $ 行(行編號從 $ 1 $ 至 $ n-1 $),第 \(i\) 行輸入一個正整數 $ a_i \((\) 0 \leq a_i \leq i $),代表第 \(i\) 個節點與第 $ a_i $ 個節點之間連有一條邊。

最后一行輸入 $ x \((\) 0 \leq x < n $),代表根節點編號。

輸出格式

輸出到標准輸出。

輸出 $ 2 $ 行,每行 $ n $ 個數,第 $ 1 $ 行代表 DFS 序,第 $ 2 $ 行代表 BFS 序。

注意:如果一個節點有多個兒子,那么應按照兒子編號遞減的順序去遍歷。

樣例1輸入

7
0
1
0
0
1
4
1

樣例1輸出

1 5 2 0 4 6 3 
1 5 2 0 4 3 6 

解:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> to[200005];
int n,a,vis[200005],q[200005],start;
int cmp(int b,int c)
{
	return b>c;
}
void ad(int u,int v)
{
	to[u].push_back(v);
}
void dfs(int k)
{
	cout << k << ' ';
	for(int i=0;i<to[k].size();i++)
	{
		if(vis[to[k][i]]==0)
		{
			vis[to[k][i]]=1;
			dfs(to[k][i]);
		}
			
	}
}
void bfs(int k)
{
	int head=1,tail=1;
	q[tail]=k;
	tail++;
	while(head<tail)
	{
		int now=q[head];
		cout << now << " ";
		head++;
		for(int i=0;i<to[now].size();i++)
		{
			if(vis[to[now][i]]==0)
			{
				vis[to[now][i]]=1;
				q[tail]=to[now][i];
				tail++;
			}
		}
	}
}
int main()
{
	cin >> n;
	for(int i=1;i<=n-1;i++)
	{
		cin >> a;
		ad(a,i);
		ad(i,a);
	}
	cin >> start;
	for(int i=0;i<n;i++)
		sort(to[i].begin(),to[i].end(),cmp);
	/*for(int i=0;i<n;i++)
	{
		for(int j=0;j<to[i].size();j++)
		cout << to[i][j] << " ";
		cout << endl;
	}*/
   //對於有根樹,將start換成根節點即可
	vis[start]=1;
	dfs(start);
	memset(vis,0,sizeof(vis));
	cout << endl;
	vis[start]=1;
	bfs(start);
return 0;
}


B.樹的直徑和中心

題目描述

給定一棵 \(n\) 個節點的無根樹(節點編號 \(0\)\(n-1\)),所有邊長均為 \(1\),求出該樹的直徑長度。

定義樹的中心為距離樹上所有節點距離的最大值最小的節點(一棵樹的中心可能不止一個),輸出該樹的中心。

輸入格式

從標准輸入讀入數據。

第一行輸入一個正整數 \(n\)\(1 \leq n \leq 200000\)),代表這棵樹的節點數目。

接下來 \(n-1\) 行(行編號從 \(1\)\(n-1\)),第 \(i\) 行輸入一個正整數 \(a_i\)\(0 \leq a_i <i\)),代表第 \(i\) 個節點與第 \(a_i\) 個節點之間連有一條邊。

輸出格式

輸出到標准輸出。

輸出 \(2\) 行,第 \(1\) 行一個整數,代表樹的直徑;第 \(2\) 行按照編號遞增順序輸出若干個整數,代表樹的中心節點編號。

樣例1輸入

6
0
1
0
0
1

樣例1輸出

3
0 1 

解:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> to[200005];
int n, a, vis[200005], q[200005], step[200005][2], head = 1, tail = 1, cen[3];
int cmp(int b, int c) { return b > c; }
void ad(int u, int v) { to[u].push_back(v); }
void bfs(int k) {
    head = 1;
    tail = 1;
    q[tail] = k;
    tail++;
    while (head < tail) {
        int now = q[head];
        head++;
        for (int i = 0; i < to[now].size(); i++) {
            if (vis[to[now][i]] == 0) {
                vis[to[now][i]] = 1;
                q[tail] = to[now][i];
                step[tail][0] = step[head - 1][0] + 1;
                step[tail][1] = head - 1;
                tail++;
            }
        }
    }
}
int main() {
    cin >> n;
    for (int i = 1; i <= n - 1; i++) {
        cin >> a;
        ad(a, i);
        ad(i, a);
    }
    for (int i = 0; i < n; i++) sort(to[i].begin(), to[i].end(), cmp);
    vis[0] = 1;
    bfs(0);
    int point = q[head - 1];
    memset(vis, 0, sizeof(vis));
    memset(step, 0, sizeof(step));
    vis[point] = 1;
    bfs(point);
    int lenth = step[tail - 1][0];
    cout << lenth << endl;
    if (lenth % 2 == 0) {
        for (int i = tail - 1; i > 0; i = step[i][1]) {
            if (step[i][0] == lenth / 2) {
                cen[1] = q[i];
                cout << cen[1] << endl;
                return 0;
            }
        }
    } else {
        for (int i = tail - 1; i > 0; i = step[i][1]) {
            if (step[i][0] == (lenth + 1) / 2) {
                cen[1] = q[i];
            }
            if (step[i][0] == (lenth - 1) / 2) {
                cen[2] = q[i];
                if (cen[2] < cen[1])
                    swap(cen[2], cen[1]);
                cout << cen[1] << " " << cen[2] << endl;
                return 0;
            }
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM