06-圖3 六度空間 (30分)
阿新 • • 發佈:2019-02-14
“六度空間”理論又稱作“六度分隔(Six Degrees of Separation)”理論。這個理論可以通俗地闡述為:“你和任何一個陌生人之間所間隔的人不會超過六個,也就是說,最多通過五個人你就能夠認識任何一個陌生人。”如圖1所示。
圖1 六度空間示意圖
“六度空間”理論雖然得到廣泛的認同,並且正在得到越來越多的應用。但是數十年來,試圖驗證這個理論始終是許多社會學家努力追求的目標。然而由於歷史的原因,這樣的研究具有太大的侷限性和困難。隨著當代人的聯絡主要依賴於電話、簡訊、微信以及因特網上即時通訊等工具,能夠體現社交網路關係的一手資料已經逐漸使得“六度空間”理論的驗證成為可能。
假如給你一個社交網路圖,請你對每個節點計算符合“六度空間”理論的結點佔結點總數的百分比。
輸入格式:
輸入第1行給出兩個正整數,分別表示社交網路圖的結點數NN(1<N≤1041<N≤10^4,表示人數)、邊數MM(≤33×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;
}