在强连通分量的判断中使用BFS
先理清楚概念:与无向图有关的是块,与有向图有关的是强连通分量
强连通分量:分量中任意两点都能相互可达
问题:在有向图中寻找某个顶点所在的的强连通分量,洛谷模板题
输入:n个点,m条边,m行输入 v x
想法:假设要找0所在的强连通分量,可能存在两种性质的点 X:由0点可达的点 Y:能到达0点的点
情形1:若存在可到达0的点,那么从该点开始在反图中进行BFS,遍历到的点都打上Y标记,结束后再从0开始BFS(原图),遍历到的点打上X标记,X和Y重合的点就是与0点在同一强连通分量内的点
情形2:不存在可到达0的点,也就是没有入度,那0点本身就是一个强连通分量
情形3:不存在可从0点出法能到达的点,也就是没有出度,那0点本身就是一个强连通分量
证明:由于强连通分量内的点两两相互可达,存在v和x,若它们相对于0点都具有重合的xy性质,那么存在路径(v, 0)(0, v), (x, 0), (0, x),也就存在(v,0,x)与(x,0,v)两条路径致使x与v相互可达
若将0点换为任意顶点,则可以查找所有的强连通分量
此方法部分受 Kosaraju 算法的启发,算是我想了小半个月的结果,但是测试下来
洛谷强连通分量链接:https://www.luogu.com.cn/problem/B3609
这是ACcode,或许可以在很多类似的题力使用,再修改一下就可以判定动态图的连通性了
点击查看代码
copy#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <fstream>
#include <sstream>
#define typedef
#define max 100001
using namespace std;
typedef struct edge
{
int v;
int x;
};
typedef struct vertex
{
int v = 1;
vector <int> in_index;
vector <int> out_index;
int x;
int y = 0;
//int b = 1;
};
void out(int c)
{
cout << c << ' ';
}
int main()
{
vector <vector<int>> s;
s.resize(1000);
int cnt = 0;
int n,m;
cin >> n >> m;
edge edge[1000]; vertex ver[1000];
for (int i = 1; i <= m; ++i)
{
cin >> edge[i].v >> edge[i].x;
ver[edge[i].v].out_index.push_back(i);
ver[edge[i].x].in_index.push_back(i);
}
queue <int> s_y;
ver[1].x = -1; //start from 1 as a root
for (int i = 1; i <= m; ++i)
{
if (edge[i].x == 1)
{
ver[edge[i].v].y = 1;//瀵绘壘鍏锋湁y鎬ц川鐨勭偣
s_y.push(edge[i].v);
}
}
queue <int> Break;//鐢ㄦ潵鍌ㄥ瓨鏂偣
for (int i = 1; i <= n; ++i)
{
Break.push(i);
}
//浠庡叿鏈墆鎬ц川鐨勭偣寮€濮嬪湪鍙嶅浘涓墿鏁?
do
{
int d = Break.front();
Break.pop();
if (ver[d].v)
{
vector <int> stack;
for (int i = 0; i < ver[d].in_index.size(); ++i)
{
s_y.push(edge[ver[d].in_index[i]].v);
}
stack.push_back(d);
ver[d].y = d; //自身具有Y性质
ver[d].v = 0; //已在分量中
if (s_y.empty())
{
cnt++;
for(int i = 0;i <stack.size();++i)
{
//cout << stack[i] << ' ';
s[cnt].push_back(stack[i]);
}
continue;
}
while(!s_y.empty())
{
int find = s_y.front();
s_y.pop();
ver[find].y = d;
//stack.push_back(find);
int l = ver[find].in_index.size();
for (int i = 0; i < l;++i)
{
int b = edge[ver[find].in_index[i]].v;
//cout << b << endl;
if (ver[b].y == d || !ver[b].v)
{
continue;
}
ver[edge[ver[find].in_index[i]].v].y = d;
//cout << b << endl;
s_y.push(b);
}
}
queue <int> search;
search.push(d);
do
{
int find_x = search.front();
search.pop();
int l = ver[find_x].out_index.size();
for(int i = 0;i < l;++i)
{
int b = edge[ver[find_x].out_index[i]].x;
if (ver[b].x == d) continue;
ver[b].x = d;
//cout << b;
/*if (ver[b].x != ver[b].y && ver[b].b)
{
Break.push(b);
ver[b].b = 0;
}else */if(/*ver[b].b * */ver[b].v && ver[b].x == ver[b].y){
ver[b].v = 0;
stack.push_back(b);
search.push(b);
}
}
}while(!search.empty());
cnt++;
//cout << cnt << " ";
sort(stack.begin(), stack.end());
for(int i = 0;i <stack.size();++i)
{
//cout << stack[i] << ' ';
s[cnt].push_back(stack[i]);
}
//cout << endl;
/*for(int i = 0;!Break.empty();++i)
{
int c = Break.front();
out(c);
Break.pop();
}*/
}
}while(!Break.empty());
cout << cnt;
cout << endl;
for (int i = 1;i <= cnt; ++i)
{
for (int j = 0;j < s[i].size(); ++j)
{
cout << s[i][j] <<' ';
}
cout << endl;
}
}
代码可以通过网站的测试,可以保证正确性,但是这个算法仍然比不过经典算法,不管是在时间上还是在空间上,这算是个比较失败的算法,不过或许可以用GPU加速呢
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步