1. 程式人生 > >06-圖3 六度空間   (30分)

06-圖3 六度空間   (30分)

“六度空間”理論又稱作“六度分隔(Six Degrees of Separation)”理論。這個理論可以通俗地闡述為:“你和任何一個陌生人之間所間隔的人不會超過六個,也就是說,最多通過五個人你就能夠認識任何一個陌生人。”如圖1所示。


圖1 六度空間示意圖

“六度空間”理論雖然得到廣泛的認同,並且正在得到越來越多的應用。但是數十年來,試圖驗證這個理論始終是許多社會學家努力追求的目標。然而由於歷史的原因,這樣的研究具有太大的侷限性和困難。隨著當代人的聯絡主要依賴於電話、簡訊、微信以及因特網上即時通訊等工具,能夠體現社交網路關係的一手資料已經逐漸使得“六度空間”理論的驗證成為可能。

假如給你一個社交網路圖,請你對每個節點計算符合“六度空間”理論的結點佔結點總數的百分比。

輸入格式:

輸入第1行給出兩個正整數,分別表示社交網路圖的結點數NN1<N≤1041<N10^4,表示人數)、邊數MM33×N,表示社交關係數)。隨後的MM行對應MM條邊,每行給出一對正整數,分別是該條邊直接連通的兩個結點的編號(節點從1到NN編號)。

輸出格式:

對每個結點輸出與該結點距離不超過6的結點數佔結點總數的百分比,精確到小數點後2位。每個結節點輸出一行,格式為“結點編號:(空格)百分比%”。

輸入樣例:

10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

輸出樣例:

1: 70.00%
2: 80.00%
3: 90.00%
4: 100.00%
5: 100.00%
6: 100.00%
7: 100.00%
8: 90.00%
9: 80.00%
10: 70.00%

解析:BFS演算法改一下,關鍵問題還是如何儲存圖,用鄰接矩陣和鄰接表問題都不大,但是鄰接表要用陣列模擬(鄰接表如果用連結串列形式儲存,訪問結點就必須遍歷,很耗時間)。另外用Floyd演算法算出所有的最短路徑,根據最短路徑是否小於等於6來判斷,但是太耗時間,最後一個最大N,M的測試點通不過。

#include <cstdio>
#include <cstdlib>
#include <queue>
#define MAX 10005
using namespace std;
//用陣列A來模擬鄰接表
int A[MAX][MAX], Visited[MAX], N, M;
//從v點開始尋找與它路徑不超過6的點的個數
int BFS(int v) {
	int V, W, last, tail, cnt, level;
	queue<int> q;
	V = v; 
	last = V;	//用來記錄每層最後一個入隊的元素
	cnt = 1;	//自己也算一個,所以設為1
	level = 0;	//記錄BFS的層數
	for(int i = 0; i < N; i++)
		Visited[i] = 0;
	Visited[V] = 1;
	q.push(V);
	while( !q.empty() ) {
		V = q.front();
		q.pop();
		for( W = 0; W < N; W++ )
			if( !Visited[W] && A[V][W] == 1 ){  //A[V][W] == 1說明邊<V, W>在鄰接表中
				Visited[W] = 1;
				q.push(W);
				tail = W;	//tail每次都記錄著最後一個入隊的元素,當V進入i層時,它指向i層末尾的元素
				cnt++;		//記錄入隊的元素個數
			}
		if( V == last ){ //last表示每層最後一個元素,當V == last,進入下一層
			level++;
			last = tail; //更新last
		}
		if( level == 6 ) //找到6層後就不必再找下去了
			break;
	}
	return cnt;
}
int main() {
	int a, b;
	float count;
	scanf("%d %d", &N, &M);
	//儲存鄰接表
	for(int i = 0; i < M; i++) {
		scanf("%d %d", &a, &b);
		--a; --b;
		A[a][b] = A[b][a] = 1;
	}
	//找到第i個人能夠認識的人數
	for(int i = 0; i < N; i++) {
		count = BFS(i);
		printf("%d: %.2f%%\n", i + 1, count / N * 100);
	}
	system("pause");
	return 0;
}