P1726 上白泽慧音 (tarjan)

题目链接:https://www.luogu.org/problem/P1726

题意:求最大强联通分量,若存在两个最大的,输出字典序最小的。

思路:裸的Tarjan算法,讲之前需要介绍一些辅助数组:

  1. dfn[ ]:表示这个点的时间戳,也就是第几个搜到的
  2. low[ ]:表示这个点能到达的最小时间戳,或者说是这个点以及其子孙节点连的所有点中dfn[ ]最小的。
  3. stack:表示当前所有可能构成强连通分量的点
  4. vis[ ]:表示一个点是否在stack中。

首先从1节点进行深度优先搜索,过程中用维护可能构成强连通分量的点。

当遇到一个点时,有如下判断:

  • 如果这个点没有访问过,就将这个点加入栈。
  • 如果这个点访问过,且在栈里,与这个点的low或dfn比较,更新自己的low。

回溯时更新low。

当一个点遍历所有的边后这个点的low还是等于dfn,将这个点及以上出栈,这个点及栈以上的点构成一个强连通分量。

这个图不一定是一个连通图,所以跑Tarjan时要枚举每个点,若dfn[ ] == 0,则继续进行Tarjan。

由于本题要输出最大强连通分量的最小字典序,我们可以用染色法将一个联通分量的点染成一个颜色,输出时直接从小到大输出即可。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
vector <int> E[N], v[N];
stack <int> sta;
int n, m, x, y, op;
int dfn[N], low[N], vis[N], color[N], col, cnt, res, flag;
void tarjan(int now)
{
    low[now] = dfn[now] = ++cnt;
    sta.push(now);
    vis[now] = 1;
    for(int i = 0; i < E[now].size(); i++)
    {
        int v = E[now][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[now] = min(low[now], low[v]);
        }
        else if(vis[v])
            low[now] = min(low[now], dfn[v]);
    }
    if(dfn[now] == low[now])
    {
        col++;
        int t = 0;
        while(1)
        {
            int tmp = sta.top(); sta.pop();
            vis[tmp]--; t++;
            color[tmp] = col;
            if(tmp == now) break;
        }
        if(t > res)
        {
            res = t;
            flag = col;
        }
    }
}
int main()
{
    scanf("%d%d",&n, &m);
    while(m--)
    {
        scanf("%d%d%d",&x, &y, &op);
        E[x].push_back(y);
        if(op == 2)
        E[y].push_back(x);
    }
    for(int i = 1; i <= n; i++)
        if(!dfn[i]) tarjan(i);
    printf("%d\n", res);
    for(int i = 1; i <= n; i++)
    {
        if(color[i] == flag)
            printf("%d ", i);
    }
}
/*
5 5
1 2 1
1 3 2
2 4 2
5 1 2
3 5 1
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值