六度空間


六度空間

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

圖1 六度空間示意圖

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

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

輸入格式:

輸入第1行給出兩個正整數,分別表示社交網絡圖的結點數N(1 < N ≤ 103 ​​ ,表示人數)、邊數M(≤ 33 × N,表示社交關系數)。隨后的M行對應M條邊,每行給出一對正整數,分別是該條邊直接連通的兩個結點的編號(節點從1到N編號)。

輸出格式:

對每個結點輸出與該結點距離不超過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%

 

解題思路

  一開始以為這道題目很難,但想了一下找到了解題思路,發現其實還蠻簡單的。當時第一反應是用DFS,不過最后一個測試點沒過。后面在網上發現這道題不能夠用DFS,因為我們不是把整一個圖都遍歷一遍,而是只遍歷指定深度的點,這會導致一些在指定深度范圍內的點范圍不到,遍歷就結束了。下面來舉個例子:

  但按照六度空間理論,這個例子中,按照路線1->3->5->6->7->8->9,頂點9也是可以訪問的。從這個例子可以看到DFS在本題中並不適用。如果要用DFS,就必須進行相應的修改。

  所以后面我改用了BFS。和原本的BFS一樣,只不過我們需要添加一個遍歷深度不超過6的條件。不過有一個難點就是,怎么知道每層的最后一個點是哪個?因為我們只有找到每層的最后那個點,深度才可以+1。

  當時我是這樣想的,設一個標識符“-1”,代表着如果從隊列中彈出“-1”就表明該層的頂點都已經訪問過了,深度需要+1,同時再把“-1”壓入隊列。

  相應的代碼如下:

 1 int BFS(LGraph *graph, int src) {
 2     bool vis[graph->verN] = {false};
 3     int depth = 0, cnt = 1; // 變量depth用來記錄遍歷的深度,cnt用來記錄從始點src開始一共可以遍歷得到的點的個數 
 4     std::queue<int> q;
 5     q.push(src);
 6     vis[src] = true;
 7     q.push(-1);             // 在把src壓入隊列后,再壓入"-1",代表src是第0層的最后一個點 
 8     
 9     while (!q.empty() && depth < 6) {   // 循環條件為隊列不為空並且深度不超過6 
10         int v = q.front();
11         q.pop();
12         if (v == -1) {      // 如果彈出的是"-1" 
13             depth++;        // 深度+1 
14             q.push(-1);     // 同時再把"-1"壓入隊列,在隊列中"-1"的前一個元素就是深度+1后那一層的最后一個點 
15             continue; 
16         }
17         
18         for (AdjVNode *w = graph->G[v]; w; w = w->next) {
19             if (!vis[w->adjVer]) {
20                 q.push(w->adjVer);
21                 vis[w->adjVer] = true;
22                 cnt++;      // 每訪問一個新的點,cnt就要+1 
23             }
24         }
25     }
26     
27     return cnt;
28 }

  姥姥還給了另外一種思路,就是用一個變量來記錄每層最后的那個點。每次在把從隊列中彈出的點的鄰接的點壓入隊列后,判斷從隊列中彈出的點是否與記錄的那個點相同,如果相同就深度+1,同時在把那個變量更新記錄當前隊列的最后一個元素,而這個元素就是該層的最后那個點。

  相應的代碼如下:

 1 int BFS(LGraph *graph, int src) {
 2     bool vis[graph->verN] = {false};
 3     int depth = 0, last = src, cnt = 1; // last用來記錄某層的最后一個點,一開始第0層的最后一個點就是src 
 4     std::queue<int> q;
 5     q.push(src);
 6     vis[src] = true;
 7     
 8     while (!q.empty() && depth < 6) {   // 循環條件為隊列不為空並且深度不超過6
 9         int v = q.front();
10         q.pop();
11         for (AdjVNode *w = graph->G[v]; w; w = w->next) {
12             if (!vis[w->adjVer]) {
13                 q.push(w->adjVer);
14                 vis[w->adjVer] = true;
15                 cnt++;
16             }
17         }
18         if (v == last) {        // 當發現某個點與last記錄的點相同,說明該層的點都已經變量過了 
19             depth++;            // 深度+1 
20             last = q.back();    // 更新last,為隊列的最后一個元素,這個元素是該層的最后那個點 
21         }
22     }
23     
24     return cnt;
25 }

  兩種版本的AC代碼如下:

 1 #include <cstdio>
 2 #include <queue>
 3 
 4 struct AdjVNode {
 5     int adjVer;
 6     AdjVNode *next;
 7 };
 8 
 9 struct LGraph {
10     AdjVNode **G;
11     int verN, edgeN;
12 };
13 
14 LGraph *createLGraph(int n, int m);
15 int BFS(LGraph *graph, int src);
16 
17 int main() {
18     int n, m;
19     scanf("%d %d", &n, &m);
20     LGraph *graph = createLGraph(n, m);
21     
22     for (int v = 0; v < graph->verN; v++) {
23         int cnt = BFS(graph, v);
24         printf("%d: %.2f%%\n", v + 1, 100.0 * cnt / graph->verN);
25     }
26     
27     return 0;
28 }
29 
30 LGraph *createLGraph(int n, int m) {
31     LGraph *graph = new LGraph;
32     graph->verN = n;
33     graph->edgeN = m;
34     graph->G = new AdjVNode*[graph->verN];
35     for (int v = 0; v < graph->verN; v++) {
36         graph->G[v] = NULL;
37     }
38     
39     for (int i = 0; i < graph->edgeN; i++) {
40         int v, w;
41         scanf("%d %d", &v, &w);
42         AdjVNode *tmp = new AdjVNode;
43         tmp->adjVer = w - 1;
44         tmp->next = graph->G[v - 1];
45         graph->G[v - 1] = tmp;
46         
47         tmp = new AdjVNode;
48         tmp->adjVer = v - 1;
49         tmp->next = graph->G[w - 1];
50         graph->G[w - 1] = tmp;
51     }
52     
53     return graph;
54 }
55 
56 int BFS(LGraph *graph, int src) {
57     bool vis[graph->verN] = {false};
58     int depth = 0, last = src, cnt = 1;
59     std::queue<int> q;
60     q.push(src);
61     vis[src] = true;
62     
63     while (!q.empty() && depth < 6) {
64         int v = q.front();
65         q.pop();
66         for (AdjVNode *w = graph->G[v]; w; w = w->next) {
67             if (!vis[w->adjVer]) {
68                 q.push(w->adjVer);
69                 vis[w->adjVer] = true;
70                 cnt++;
71             }
72         }
73         if (v == last) {
74             depth++;
75             last = q.back();
76         }
77     }
78     
79     return cnt;
80 }

 1 #include <cstdio>
 2 #include <queue>
 3 
 4 struct AdjVNode {
 5     int adjVer;
 6     AdjVNode *next;
 7 };
 8 
 9 struct LGraph {
10     AdjVNode **G;
11     int verN, edgeN;
12 };
13 
14 LGraph *createLGraph(int n, int m);
15 int BFS(LGraph *graph, int src);
16 
17 int main() {
18     int n, m;
19     scanf("%d %d", &n, &m);
20     LGraph *graph = createLGraph(n, m);
21     
22     for (int v = 0; v < graph->verN; v++) {
23         int cnt = BFS(graph, v);
24         printf("%d: %.2f%%\n", v + 1, 100.0 * cnt / graph->verN);
25     }
26     
27     return 0;
28 }
29 
30 LGraph *createLGraph(int n, int m) {
31     LGraph *graph = new LGraph;
32     graph->verN = n;
33     graph->edgeN = m;
34     graph->G = new AdjVNode*[graph->verN];
35     for (int v = 0; v < graph->verN; v++) {
36         graph->G[v] = NULL;
37     }
38     
39     for (int i = 0; i < graph->edgeN; i++) {
40         int v, w;
41         scanf("%d %d", &v, &w);
42         AdjVNode *tmp = new AdjVNode;
43         tmp->adjVer = w - 1;
44         tmp->next = graph->G[v - 1];
45         graph->G[v - 1] = tmp;
46         
47         tmp = new AdjVNode;
48         tmp->adjVer = v - 1;
49         tmp->next = graph->G[w - 1];
50         graph->G[w - 1] = tmp;
51     }
52     
53     return graph;
54 }
55 
56 int BFS(LGraph *graph, int src) {
57     bool vis[graph->verN] = {false};
58     int depth = 0, cnt = 1;
59     std::queue<int> q;
60     q.push(src);
61     vis[src] = true;
62     q.push(-1);
63     
64     while (!q.empty() && depth < 6) {
65         int v = q.front();
66         q.pop();
67         if (v == -1) {
68             depth++;
69             q.push(-1);
70             continue;
71         }
72         
73         for (AdjVNode *w = graph->G[v]; w; w = w->next) {
74             if (!vis[w->adjVer]) {
75                 q.push(w->adjVer);
76                 vis[w->adjVer] = true;
77                 cnt++;
78             }
79         }
80     }
81     
82     return cnt;
83 }

 

參考資料

  浙江大學——數據結構:https://www.icourse163.org/course/ZJU-93001?tid=1461682474

  [小白向]PTA 06-圖3 六度空間 (30分)DFS通過測試點4:https://blog.csdn.net/yine100320/article/details/107959177


免責聲明!

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



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