构建图的头文件见 Graph.h
判断是否有环
采用dfs搜索,维护三个顶点信息,【上一个已访问节点,当前节点,下一个】。直接的,当【下一个】已经被标记且不是【上一个】,说明有环。因为,被标记节点【上一个】,【下一个】属于一个联通子图,即有路径相连。
Cycle.h
#pragma once
#include"Graph.h"
class Cycle
{
private:
vector<int>* m_visited = nullptr;
bool m_hasCycle = false;
void dfs(Graph& G, int now, int pre);
public:
Cycle() {}
Cycle(Graph& G);
bool hasCycle() { return m_hasCycle; }
};
void Cycle::dfs(Graph& G, int now, int pre)
{
m_visited->at(now) = 1;
for (auto next : G.adj(now) ) {
if (!m_visited->at(next)) {
dfs(G, next, now);
}
else if (next != pre) {
m_hasCycle = true;
}
}
}
Cycle::Cycle(Graph& G)
{
int n = G.V();
m_visited = new vector<int>(n, 0);
for (int i = 0; i < n; i++) {
if (!m_visited->at(i)) {
dfs(G, i, i);
}
}
}
void testCycle()
{
Graph G("data.txt");
Cycle cle(G);
printf_s("has cycle ? "), cout<<(cle.hasCycle())<<endl;
}
二分图问题
用两种颜色上色,并且保证相同颜色的节点不相邻,能这样上色的就是二分图。例如,演员和电影的关系图,电影电影之间要通过演员连接。
方法:用dfs搜索,保证【now,next】颜色不同。当出现【now】和【next】都已经标记,且同色,涂色失败,即不可能是二分图。
TwoColor.h
#pragma once
#include"Graph.h"
class TwoColor
{
private:
vector<bool>* m_visited = nullptr;
vector<bool>* m_color = nullptr;
bool m_isTwoColorable = true;
void dfs(Graph& G, int v);
public:
TwoColor() {}
TwoColor(Graph& G);
bool isBipartite() {
return m_isTwoColorable;
}
};
void TwoColor::dfs(Graph& G, int v)
{
m_visited->at(v) = true;
for (auto& next : G.adj(v)) {
if (!m_visited->at(next)) {
m_color->at(next) = !m_color->at(v);
dfs(G, next);
}//孩子已经标记且和父亲同色
else if (m_color->at(next) == m_color->at(v)) {
m_isTwoColorable = false;
}
}
}
TwoColor::TwoColor(Graph& G)
{
m_visited = new vector<bool>(G.V(), false);
m_color = new vector<bool>(G.V(), false);
for (int i = 0; i < G.V(); ++i) {
//遍历所有节点去涂色
if (!m_visited->at(i)) {
dfs(G, i);
}
}
}
//测试当前的类
void testTwoColor()
{
Graph G("data.txt");
TwoColor two(G);
cout << (two.isBipartite()) << endl;
}
data.txt
6
6
1 3
3 5
1 4
4 5
2 4
0 5