在强连通分量的判断中使用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 算法的启发,算是我想了小半个月的结果,但是测试下来

image
洛谷强连通分量链接: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加速呢

posted @   hendry_0702  阅读(5)  评论(0编辑  收藏  举报
相关博文:
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起