1. 程式人生 > 其它 >測試計劃包含哪些內容

測試計劃包含哪些內容

樹的重心定義

對於一棵無根樹,任選一個點為根節點,以根節點為分界,得到若干個子樹,具有結點數最多的子樹就是最大子樹。以每個點為根節點,最大子樹中結點數最小的那個根節點就是樹的重心。(百度定義:樹的重心也叫樹的質心。找到一個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心)
或者樹的重心還可以定義為:去掉該結點後,樹的各個連通分支中含有的結點最小。

以下圖為例:

以1當作根節點,其所有子樹的結點數為3,3,2。1的最大子樹就是3。
1就是樹的重心,因為以其他點為根節點時,最大子樹的結點數都會超過3
如以2為根節點,最大子樹為{1,2,4,7,8,9}

輸入輸出
輸入:第一行一個整數n,表示樹的結點個數。
接下來n-1行,每行兩個數i,j。表示i和j有邊相連。
輸出:第一行一個整數k,表示重心的個數。
接下來K行,每行一個整數,表示重心。按從小到大的順序給出。

思路

任選一個結點作為根節點,用DFS進行遍歷,求出所有結點的子樹大小(大小就是子樹所含的結點數),所有結點還有一個到根節點的子樹,大小為總結點數-當前結點所含所有子樹的大小。求出每個結點最大子樹的結點數,再求最小值。

int sz[N],mx[N];	//sz[i]是以i為根節點的子樹大小,mx[i]是以i為根節點的子樹的最大子樹大小
void dfs(int u,int pre){
	sz[u] = 1;	//自己也要算進去
	mx[u] = 0;
	for(int i = head[u];i;i = nxt[i]){
		int v = ver[i];
		if(v == pre) continue;
		dfs(v,u);
		sz[u] += sz[v];	//dfs搜尋完v之後,更新sz[u]
		mx[u] = max(mx[u],sz[v]);	//更新最大子樹的大小
	}
	mx[u] = max(mx[u], n-sz[u]);	//還要與到根節點那顆子樹的大小比較
}

樹的重心的性質

  1. 一棵樹最少有一個重心,最多有兩個重心,若有兩個重心,則它們相鄰(即連有直接邊)。
  2. 樹上所有點到某個點的距離和裡,到重心的距離和最小;若有兩個重心,則其距離和相同。
  3. 若以重心為根,則所有子樹的大小都不超過整棵樹的一半。否則可以通過平移使得最大子樹的大小縮小至整樹的一半,剩下子樹的大小最大為 n/2−1 。此時新平移到的點才是真正的重心。
  4. 在一棵樹上新增或刪除一個葉子節點,其重心最多平移一條邊的距離。
  5. 兩棵樹通過連一條邊組合成新樹,則新樹重心在原來兩棵樹的重心的連線上。

解題

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110;
int tot;
int head[N],ver[N],nxt[N];	//鄰接表建樹需要的陣列 
int sz[N],mx[N];	//sz是以i為根節點的子樹的大小,mx是每個點的最大子樹大小 

void addedge(int u,int v){	//鄰接表建樹過程 
	tot++;
	nxt[tot] = head[u];
	ver[tot] = v;
	head[u] = tot;
}
int n, minn = 1e8;
void dfs(int u,int pre){
	sz[u] = 1;	//自己也要算進去
	mx[u] = 0;
	for(int i = head[u];i;i = nxt[i]){
		int v = ver[i];
		if(v == pre) continue;
		dfs(v,u);
		sz[u] += sz[v];	//dfs搜尋完v之後,更新sz[u]
		mx[u] = max(mx[u],sz[v]);	//更新最大子樹的大小
	}
	mx[u] = max(mx[u], n-sz[u]);	//還要與到根節點那顆子樹的大小比較
	if(mx[u] < minn)  minn = mx[u];
}

int main()
{
    int u,v;
    cin >> n;
    for(int i = 1;i <= n-1;i++){	//建立邊 
    	cin >> u >> v;
    	addedge(u,v);
	}
	dfs(1,0);	//進行dfs遍歷 
	int len=0,p[2];
	for(int i = 1;i <= n;i++){	//尋找樹的重心 
		if(mx[i] == minn)
			p[len++] = i;
	}
	cout << len << endl;	//輸出 
	for(int i = 0;i < len;i++){
		cout << p[i] << endl;
	}
}
作者:inss!w! 出處:https://www.cnblogs.com/Hfolsvh/ 版權宣告:本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協議。轉載請註明出處!