C++で有向グラフが連結しているかどうかを判定する方法
グラフの連結性(接続性)を確認するには、何らかの探索アルゴリズムを使ってすべてのノードを巡回してみます。探索が完了した時点で、まだ訪問されていないノードが1つでも残っていれば、そのグラフは連結していないと判断できます。
有向グラフの場合は、すべてのノードから順に探索を開始して連結性をチェックします。これは、あるエッジが外向きの辺しか持たず内向きの辺を持たない場合、そのノードには他のどの開始ノードからも到達できない可能性があるためです。
本記事では、この探索アルゴリズムとして再帰的なDFS(深さ優先探索)を使用します。
入力と出力
入力 − グラフの隣接行列
| 0 | 1 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 |
| 0 | 0 | 0 | 1 | 1 |
| 1 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 | 0 |
出力 − グラフは連結しています。
アルゴリズム
traverse(u, visited)
入力: 開始ノード u と、訪問済みノードを記録する visited 配列
出力: 到達可能なすべての頂点を巡回する
traverse(u, visited)
Begin
u を訪問済みとしてマークする
u に隣接するすべての頂点 v について、以下を実行する
v が未訪問であれば
traverse(v, visited) を呼び出す
完了
EndisConnected(graph)
入力: グラフ
出力: グラフが連結していれば true、そうでなければ false
isConnected(graph)
Begin
visited 配列を定義する
グラフ内のすべての頂点 u について、以下を実行する
すべてのノードを未訪問状態に初期化する
traverse(u, visited) を実行する
未訪問のノードがまだ残っている場合は
false を返す
完了
true を返す
EndC++による実装例
#include<iostream>
#define NODE 5
using namespace std;
int graph[NODE][NODE] = {{0, 1, 0, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 0, 1, 1},
{1, 0, 0, 0, 0},
{0, 1, 0, 0, 0}
};
void traverse(int u, bool visited[]){
visited[u] = true; // u を訪問済みとしてマーク
for(int v = 0; v<NODE; v++){
if(graph[u][v]){
if(!visited[v])
traverse(v, visited);
}
}
}
bool isConnected(){
bool *vis = new bool[NODE];
// すべての頂点 u を開始点として、全ノードが訪問できるか確認する
for(int u = 0; u < NODE; u++){
for(int i = 0; i<NODE; i++)
vis[i] = false; // すべてのノードを未訪問として初期化
traverse(u, vis);
for(int i = 0; i<NODE; i++){
if(!vis[i]) // 探索で訪問されなかったノードがあれば、グラフは非連結
return false;
}
}
return true;
}
int main(){
if(isConnected())
cout << "The Graph is connected.";
else
cout << "The Graph is not connected.";
}実行結果
The Graph is connected.
解説
このプログラムでは、まず traverse 関数が再帰的なDFSを実装しています。開始ノードを訪問済みにマークし、隣接する未訪問ノードに対して再帰的に自分自身を呼び出すことで、到達可能なすべての頂点を巡回します。
isConnected 関数では、各頂点を開始点として探索を行い、毎回 visited 配列をリセットします。5つの頂点それぞれから探索しても全ノードに到達できれば、その有向グラフは強連結であると判定できます。計算量は O(V × (V + E)) となり、V は頂点数、E はエッジ数です。
-
C++で有向グラフの強連結成分を検出するプログラムの作成方法
有向グラフにおいて、ある成分内の任意の頂点ペア同士の間に経路が存在するとき、その成分は「強く接続されている(強連結)」といいます。このような成分のことを強連結成分(SCC: Strongly Connected Components)と呼びます。この問題を解くには、まずDFS(深さ優先探索)を使って各頂点の完了時刻(finish time)を求めます。次にグラフを転置し、完了時刻をもとに頂点を降順に並べる(トポロジカルソート)ことで、強連結成分を一つずつ取り出します。これは有名なKosarajuのアルゴリズムに基づいた手法です。入力: グラフの隣接行列001101000001000000010
-
DFS(深さ優先探索)による有向グラフの連結性チェック ― C++プログラム解説
グラフの連結性チェックの基本概念 グラフが連結しているかどうかを調べるには、何らかの探索アルゴリズムを用いてすべてのノードを巡回してみます。探索が完了した時点で、まだ一度も訪問されていないノードが残っていれば、そのグラフは連結ではないと判断できます。 有向グラフの場合のポイント 無向グラフと異なり、有向グラフの場合はすべてのノードを起点として探索を行う必要があります。理由は、あるエッジが外向きの辺しか持たず、内向きの辺を持たないケースが存在するためです。そのようなノードは、他のどのノードを出発点としても到達できない可能性があります。 本記事では、探索アルゴリズムとして再帰的なDFS(深さ優先