洛谷P1726 上白泽慧音 tarjan

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

tarjan的一道模板题,t=1连一条单向边,t=2连一条双向边。tarjan跑一遍,一个绝对连通区域就是一个强连通分量。tarjan中每次找到一个强连通分量,记录这个强连通分量有多少个点。然后找到强连通分量最大的那个,从前往后找,就保证了字典序最小的优先,最后输出属于那个连通块的点即可。
代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e3+5;
const int maxm=1e5+5;
int head[maxn];
struct node
{
    int to,next;
}edge[maxm];
int cnt;
void add(int x,int y)
{
    edge[++cnt].next=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
}
int dfn_number,top,color;
int dfn[maxn],low[maxn],col[maxn],stc[maxn],col_num[maxn];
bool vis[maxn];
void tarjan(int u)
{
    dfn[u]=low[u]=++dfn_number;
    stc[++top]=u;
    vis[u]=1;
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
        low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        int len=1;
        vis[u]=false;
        col[u]=++color;
        while(stc[top]!=u)
        {
            vis[stc[top]]=false;
            col[stc[top--]]=color;
            len++;
        }
        top--;
        col_num[color]=len;
    }
}
int n,m;
int opt,x,y;
int main()
{
    scanf("%d %d",&n,&m);
    while(m--)
    {
        scanf("%d %d %d",&x,&y,&opt);
        if(opt==1)
        {
            add(x,y);
        }
        else
        {
            add(x,y);
            add(y,x);
        }
    }
    for(int i=1;i<=n;i++)
    if(!dfn[i])
    tarjan(i);
    int ma=0,t;
    for(int i=1;i<=n;i++)
    {
        if(col_num[col[i]]>ma)
        {
            ma=col_num[col[i]];
            t=col[i];
        }
        //cout<<col[i]<<endl;
    }
    printf("%d\n",ma);
    for(int i=1;i<=n;i++)
    {
        if(col[i]==t)
        printf("%d ",i);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44491423/article/details/104761277
今日推荐