边双联通分量:在一个无向图中,存在一个极大子图,删除任意一条边之后仍然是一个无向图。
桥:在无向图中,存在某条边,删除该边之后,该无向图将会被分割成两个无向图。
1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 #include <map> 7 #include <algorithm> 8 9 using namespace std; 10 11 #define ll long long 12 #define pb push_back 13 #define fi first 14 #define se second 15 16 const int N = 1e5 + 10; 17 int dfn[N]; //时间戳 18 int low[N]; //能到达最早点 19 int s[N]; //栈 20 int scc_no[N];//属于哪个scc 21 int scc_cnt[N]; //该scc有几个点 22 vector<int > scc[N];//缩点 23 vector<int > E[N]; //边 24 vector<int > new_E[N];//缩点后的图 25 int boss[N]; 26 int SCC; //第几个scc 27 int tim;//dfs序号 28 int top;//栈顶 29 int cut_cnt; //割桥数 30 int n, m; //点数 边数 31 struct _cut{ 32 int x, y; 33 }; 34 vector<_cut > cut;//桥 35 36 //时间复杂度 O(m) 37 //无向图中求的是边双联通分量,ins[]数组没作用 38 39 void init(){ 40 for(int i = 0; i <= n; ++i){ 41 dfn[i] = low[i] = 0; 42 scc_cnt[i] = 0; 43 scc_no[i] = 0; 44 scc[i].clear(); 45 E[i].clear(); 46 } 47 SCC = tim = top = cut_cnt = 0; 48 cut.clear(); 49 } 50 51 void tarjan(int now, int pre){ 52 dfn[now] = low[now] = ++tim; 53 s[top++] = now; 54 55 int pre_cnt = 0; 56 for(auto to : E[now]){ 57 //处理一条无向边 58 if(to == pre && pre_cnt == 0) { pre_cnt = 1; continue; } 59 60 if(!dfn[to]){ 61 tarjan(to, now); 62 low[now] = min(low[now], low[to]); 63 64 //to不能到达 now或者now之前的点 65 if(dfn[now] < low[to]){ 66 cut.pb(_cut{now, to}); 67 } 68 69 }else low[now] = min(low[now], dfn[to]); 70 } 71 72 if(dfn[now] == low[now]){ 73 int sum = 0; //该scc的点数 74 ++SCC;//第几个scc 75 boss[SCC] = now; 76 int tmp;//暂存点 77 78 do{ 79 tmp = s[--top];//取点 80 ++sum;//点数++ 81 scc_no[tmp] = SCC;//属于哪个scc 82 //scc[SCC].pb(tmp);//放入这个连通图,缩点 83 }while(tmp != now); 84 //scc_cnt[SCC] = sum;//该scc的点数 85 } 86 } 87 //桥信息 88 void show_info(){ 89 printf("cut bridge = (%d) ", cut_cnt); 90 for(auto c : cut){ 91 printf("(%d - %d) ", c.x, c.y); 92 } 93 } 94 95 void solve(){ 96 97 //int _case = 0; 98 while(~scanf("%d%d", &n, &m) && (n + m)){ 99 //scanf("%d%d", &n, &m); 100 //初始化每组数据 101 init(); 102 103 //读边 104 for(int i = 1; i <= m; ++i){ 105 int u, v; 106 scanf("%d%d", &u, &v); 107 E[u].pb(v); 108 E[v].pb(u); 109 } 110 111 //可能不是一个连通图 112 for(int now = 1; now <= n; ++now){ 113 if(!dfn[now]){ 114 tarjan(now, now); 115 } 116 } 117 118 cut_cnt = cut.size(); 119 120 show_info(); 121 } 122 } 123 124 int main(){ 125 126 solve(); 127 //cout << "not error" << endl; 128 return 0; 129 }