edo1z blog

プログラミングなどに関するブログです

C++ グラフ・探索

参考サイト

DFS (深さ優先探索) 超入門! 〜 グラフ・アルゴリズムの世界への入口 〜【前編】 - Qiita

グラフを隣接リストで表す

隣接リストは、各頂点毎に、隣接する頂点の配列を作ります。

#include <bits/stdc++.h>
using namespace std;
using Graph = vector<vector<int>>;

int main()
{
  Graph G;
  G.at(0) = {1, 2};
  G.at(1) = {0, 2, 3};
  G.at(2) = {0, 1, 4};
  G.at(3) = {1, 4, 5};
  G.at(4) = {2, 3, 6};
  G.at(5) = {3};
  G.at(6) = {4};
}

0と1はお互いがお互いを配列に入れてるので、これは無向グラフ。有効グラフの場合はどちらかに入る。

BFS(幅優先探索)

サンプルコード

#include <bits/stdc++.h>
using namespace std;
using Graph = vector<vector<int>>;

Graph G(7);
vector<bool> seen;
vector<int>  todo;

void bfs()
{
  while(todo.size() > 0)
  {
    // todoからFIFOでvを取り出す
    int v = todo.at(0);
    todo.erase(todo.begin());

    cout <<  v << ' ';
    for (int next_v : G.at(v))
    {
      if (seen.at(next_v)) continue;
      seen.at(next_v) = true;
      todo.push_back(next_v);
    }
  }
}

int main()
{
  G.at(0) = {1, 2};
  G.at(1) = {0, 2, 3};
  G.at(2) = {0, 1, 4};
  G.at(3) = {1, 4, 5};
  G.at(4) = {2, 3, 6};
  G.at(5) = {3};
  G.at(6) = {4};

  seen.assign(7, false);
  seen.at(0) = true;
  todo.push_back(0);
  bfs();
}

結果

0 1 2 3 4 5 6 

DFS(深さ優先探索)

上記のBFSのコードの下記部分を変更する。

変更前(BFS)

// todoからFIFOでvを取り出す
int v = todo.at(0);
todo.erase(todo.begin());

変更後(DFS)

// todoからLIFOでvを取り出す
int v = todo.at(todo.size() - 1);
todo.pop_back();

サンプルコード

#include <bits/stdc++.h>
using namespace std;
using Graph = vector<vector<int>>;

Graph G(7);
vector<bool> seen;
vector<int>  todo;

void dfs()
{
  while(todo.size() > 0)
  {
    // todoからLIFOでvを取り出す
    int v = todo.at(todo.size() - 1);
    todo.pop_back();

    cout <<  v << ' ';
    for (int next_v : G.at(v))
    {
      if (seen.at(next_v)) continue;
      seen.at(next_v) = true;
      todo.push_back(next_v);
    }
  }
}

int main()
{
  G.at(0) = {1, 2};
  G.at(1) = {0, 2, 3};
  G.at(2) = {0, 1, 4};
  G.at(3) = {1, 4, 5};
  G.at(4) = {2, 3, 6};
  G.at(5) = {3};
  G.at(6) = {4};

  seen.assign(7, false);
  seen.at(0) = true;
  todo.push_back(0);
  dfs();
}

結果

0 2 4 6 3 5 1 

DFS(再帰を使う場合)

サンプルコード

#include <bits/stdc++.h>
using namespace std;
using Graph = vector<vector<int>>;

void dfs(const Graph &G, vector<bool> &seen, int v)
{
  cout << v << ' ';
  seen.at(v) = true;
  for (auto next_v : G.at(v))
  {
    if (seen.at(next_v)) continue;
    dfs(G, seen, next_v);
  }
}

int main()
{
  Graph G(7);
  G.at(0) = {1, 2};
  G.at(1) = {0, 2, 3};
  G.at(2) = {0, 1, 4};
  G.at(3) = {1, 4, 5};
  G.at(4) = {2, 3, 6};
  G.at(5) = {3};
  G.at(6) = {4};

  vector<bool> seen(G.size(), false);
  dfs(G, seen, 0);
}

結果

0 1 2 4 3 5 6