Tarjan入门④-双连通分量(下)(T103492)

接上文,说一下如何求点双.

思路:

要注意一点的是:点双连通分量之间是有公共点的(而且一定是割点)。所以,栈需要记录生成树上的边,而不是点

改动点:

1.当 d f n [ v ] = = 0 dfn[v] == 0 dfn[v]==0时,边入栈.

2.当 d f n [ u ] ≤ l o w [ v ] , v ∈ u 的 后 继 时 dfn[u] \leq low[v],v \in u的后继时 dfn[u]low[v],vu,代表着 u u u连接着的 v v v的这颗子树无法不通过父节点回到更早的时候,即 u ∪ 子 树 v u\cup 子树v uv构成了一个点双。此时,栈顶存着这个连通分量中的所有边.以此弹出染色即可。

3.千万注意:单个点也是点双.所以做题的时候要考虑图是否连通。

模板题:T103492
题目大意:

给你一张无向图,查询所有点双.

题目思路:

没说连通,那么要特判单个点的情况.

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 5;
const int maxm = 6e5 + 5;
int u[maxm] , v[maxm] , nextt[maxm] ,first[maxn] , sign;
void addedge(int x , int y){u[++sign]=x;v[sign]=y;nextt[sign]=first[x];first[x]=sign;}
int n , m;
int dfn[maxn] , low[maxn] , cnt , tot;
struct Edge {int x , y;};
vector<int> res[maxn];
stack<Edge> s;
void tarjan (int g , int fa)
{
    dfn[g] = low[g] = ++cnt;
    if (first[g] == 0) {
        res[++tot].push_back(g);
    }
    for (int i = first[g] ; i ; i = nextt[i]){
        if (!dfn[v[i]]){
            s.push({g , v[i]});
            tarjan(v[i] , g);
            if (dfn[g] <= low[v[i]]){
                ++tot;
                while (1){
                    Edge now = s.top();s.pop();
                    res[tot].push_back(now.y);
                    if (now.x == g) {
                        res[tot].push_back(g);
                        break;
                    }
                }
            }
            low[g] = min (low[g] , low[v[i]]);
        }else
            low[g] = min (low[g] , dfn[v[i]]);

    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1 ; i <= m ; i++){
        int x , y; cin >> x >> y;
        addedge(x , y);
        addedge(y , x);
    }
    for (int i = 1 ; i <= n ; i++){
        if (!dfn[i]) tarjan(i , 0);
    }
    for (int i = 1 ; i <= tot ; i++){
        for (auto g : res[i]) cout << g << " ";
        cout << endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值