給定圖中移除 Q 個頂點後連通分量的數量
連通分量的數量表示在移除指定的Q個頂點後,圖中剩餘頂點所形成的非連通子圖的數量。各個分量之間沒有邊連線;每個連通分量都由透過邊連線的一組頂點組成。移除Q個頂點後,某些頂點可能會變得孤立,導致連線斷裂並形成新的分量。該方法旨在確定最終將有多少個非連通子圖。許多應用都需要了解連通分量的數量,包括網路分析、社交網路研究和最佳化演算法。
使用的方法
Kosaraju 演算法
基於矩陣的方法
Kosaraju 演算法
從圖中刪除指定的Q個頂點後,使用 Kosaraju 演算法來確定網路中的連通分量數量。它使用兩遍深度優先搜尋 (DFS)。第一遍遍歷原始圖以獲得每個頂點的“完成時間”。在第二遍中,圖被轉置(所有邊的方向都反轉),並且從完成時間最高的頂點開始對轉置後的圖應用 DFS。該方法確定了更改後的圖中連通分量的數量,透過在過程中忽略已移除的Q個頂點,揭示了頂點移除後非連通子圖的數量。
演算法
建立一個空棧來儲存第一次 DFS 遍歷的頂點。
在原始圖上執行第一次 DFS 遍歷
從一個未探索的頂點開始,使用 DFS 探索一個連通頂點的分量。
當一個頂點的所有相鄰頂點都被訪問後,標記訪問該頂點並將其壓入棧中。
反轉每條邊的方向以轉置圖。
為第二次 DFS 遍歷建立一個布林陣列來跟蹤已訪問的頂點。
在修改後的圖上執行第二次 DFS 遍歷
從棧中依次移除每個頂點。
如果一個頂點尚未被訪問或刪除(不在Q中),則使用 DFS 探索該頂點的相關分量。在此過程中,標記已訪問的頂點。
移除 Q 個頂點後,連通分量的數量等於第二次 DFS 被呼叫的次數。
移除 Q 個頂點後,該過程會生成網路中連通分量的數量。
示例
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
void dfs1(int vertex, vector<vector<int>>& graph, vector<bool>& visited, stack<int>& stk) {
visited[vertex] = true;
for (int neighbor : graph[vertex]) {
if (!visited[neighbor])
dfs1(neighbor, graph, visited, stk);
}
stk.push(vertex);
}
void dfs2(int vertex, vector<vector<int>>& transpose_graph, vector<bool>& visited) {
visited[vertex] = true;
for (int neighbor : transpose_graph[vertex]) {
if (!visited[neighbor])
dfs2(neighbor, transpose_graph, visited);
}
}
int kosaraju(int N, vector<vector<int>>& graph, vector<vector<int>>& transpose_graph, vector<int>& Q) {
vector<bool> visited(N + 1, false);
stack<int> stk;
for (int i = 1; i <= N; i++) {
if (!visited[i])
dfs1(i, graph, visited, stk);
}
fill(visited.begin(), visited.end(), false);
for (int i = 0; i < Q.size(); i++) {
visited[Q[i]] = true;
}
int count = 0;
while (!stk.empty()) {
int vertex = stk.top();
stk.pop();
if (!visited[vertex]) {
dfs2(vertex, transpose_graph, visited);
count++;
}
}
return count;
}
int main() {
int N = 7;
int M = 8;
int E = 2;
vector<vector<int>> graph(N + 1);
vector<vector<int>> transpose_graph(N + 1);
vector<pair<int, int>> edges = {{1, 2}, {2, 3}, {3, 1}, {2, 4}, {4, 5}, {5, 6}, {6, 4}, {7, 6}};
for (const auto& edge : edges) {
int u = edge.first;
int v = edge.second;
graph[u].push_back(v);
transpose_graph[v].push_back(u);
}
vector<int> Q = {3, 4};
int result = kosaraju(N, graph, transpose_graph, Q);
cout << result << endl;
return 0;
}
輸出
5
基於矩陣的方法
基於矩陣的方法使用鄰接矩陣或鄰接表來表示圖。然後,從矩陣中移除指定的 Q 個頂點。然後,透過對修改後的圖使用圖遍歷演算法(如深度優先搜尋 (DFS) 或廣度優先搜尋 (BFS))來確定連通分量的數量。記錄已遍歷的頂點以避免重新處理。移除 Q 個頂點後,圖中連通分量的數量對應於遍歷方法執行的次數。對於不同的圖分析和網路相關應用,此方法有效地計算連通分量數量。
演算法
使用鄰接矩陣或鄰接表來表示圖。
透過從矩陣或列表中移除指定的 Q 個頂點來生成修改後的圖。
設定一個變數來跟蹤連通分量的數量。
最初遍歷更新後的圖中的每個頂點。
從每個未探索的頂點應用圖遍歷演算法 (DFS 或 BFS)。
標記在遍歷期間訪問的頂點以避免重新處理。
繼續遍歷,直到所有與初始頂點相關的頂點都被訪問。
對於發現的每個獨特的互連頂點集,在方程中將連通分量的數量增加 1。
根據需要重複步驟 5 到 8,以訪問更新後的圖中的每個頂點。
移除所需頂點後,圖中非連通子圖的總數由連通分量數量的最終值表示。
示例
#include <iostream>
#include <vector>
using namespace std;
void dfs(vector<vector<int>>& graph, vector<bool>& visited, int node) {
visited[node] = true;
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
dfs(graph, visited, neighbor);
}
}
}
int countReachableNodes(vector<vector<int>>& graph) {
int N = graph.size();
vector<bool> visited(N, false);
int count = 0;
for (int i = 0; i < N; ++i) {
if (!visited[i]) {
dfs(graph, visited, i);
count++;
}
}
return count;
}
int main() {
// Create the graph (Adjacency List representation)
vector<vector<int>> graph = {
{1},
{0, 2},
{1},
{4},
{3}
};
int reachableNodes = countReachableNodes(graph);
cout << "Number of nodes accessible from all other nodes: " << reachableNodes << endl;
return 0;
}
輸出
Number of nodes accessible from all other nodes: 2
結論
總之,在移除一定數量的頂點後,圖中剩餘的連通分量數量是網路分析和相關領域中的一個關鍵指標。基於矩陣的方法和 Kosaraju 演算法都提供了計算此數量的有效方法。基於矩陣的方法使用 DFS 或 BFS 等圖遍歷演算法在重新設計的圖上有效地找到連通分量,而 Kosaraju 演算法使用兩遍深度優先搜尋來識別強連通分量。即使在移除某些頂點後,這兩種方法也能產生可靠的結果,有助於理解圖的連線性和結構特徵。選擇使用哪種方法取決於圖的屬性和當前問題的具體要求。
資料結構
網路
關係資料庫管理系統 (RDBMS)
作業系統
Java
iOS
HTML
CSS
Android
Python
C語言程式設計
C++
C#
MongoDB
MySQL
Javascript
PHP