Tarjan (in-degree, strong connectivity)

Today is the fourth session of the Harbin Institute of Technology’s winter vacation algorithm training camp, and some basic problems of graph theory have been asked. As for the title, you can probably understand the meaning. but myself
Limited strength, can only read (manually funny.
Let's get to the topic first:

The title is easy to read. According to the meaning of the question, we only need to judge whether we can connect to each strongly connected block.

Here is a blog that explains the Tarjan algorithm in detail: http://blog.csdn.net/qq_34374664/article/details/77488976
As a newbie, I can't explain it clearly (smile.png

Let's take a look at the code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1010;
int Laxt[maxn],Next[maxn*250],To[maxn*250],cnt,n,m;
int dfn[maxn],low[maxn],times,scc_cnt,scc[maxn];
int instc[maxn],stc[maxn],top;
int ind[maxn],ans,p[maxn],ok[maxn];
void update()
{
    cnt=times=scc_cnt=top=ans=0;
    memset(Laxt,0,sizeof(Laxt));
    memset(dfn,0,sizeof(dfn));
    memset(scc,0,sizeof(scc));
    memset(instc,0,sizeof(instc));
    memset(stc,0,sizeof(stc));
    memset(ind,0,sizeof(ind));
    memset(p,0,sizeof(p));
    memset(ok,0,sizeof(ok));
}
void add(int u,int v)//链式向前星 构图
{
    Next[++cnt]=Laxt[u];
    Laxt[u]=cnt;
    To[cnt]=v;
}
void dfs(int u)//Tarjan算法核心代码 
{
    dfn[u]=low[u]=++times;
    stc[++top]=u;
    instc[u]=1;
    for(int i=Laxt[u]; i; i=Next[i])
    {
        int v=To[i];
        if(!dfn[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instc[v])//有向图和无向图的区别
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        scc_cnt++;//找到一个强连通块就 记录下来
        while(true)
        {
            int x=stc[top--];
            scc[x]=scc_cnt;
            instc[x]=0;
            if(x==u) break;
        }
    }
}
void tarjan()
{
    for(int i=1; i<=n; i++)
        if(!dfn[i]) dfs(i);
    for(int i=1; i<=n; i++)
        for(int j=Laxt[i]; j; j=Next[j])
        {
            if(scc[i]!=scc[To[j]])//一条边上的两个点 不在一个联通块里
            {
                ind[scc[To[j]]]++;//入度 自增一次  就代表能够通知到这个强连通块
                //这里没必要重新构图 题目只需要求入度而已
            }
        }

    for(int i=1; i<=scc_cnt; i++)
    {
        if(ind[i]==0) ans++;//这里判断入度为0的强连通块  
    }
    if(ans>m)// 个数大于 能通知到的个数 直接退出且输出-1
    {
        printf("-1\n");
        return ;
    }
    for(int i=1; i<=n; i++)
    {
        if(ind[scc[i]]==0&&p[i]==1) ok[scc[i]]=1;//这里我们判断如果这个点入度为0  p数组是前面记录了最开始通知到的M个人 
    }
    for(int i=1; i<=scc_cnt; i++)
        if(ind[i]==0&&!ok[i])//如果这个强连通块入度为0 并且也不是最开始通知到的联通块 那么这个强连通块就联系不到了
        {
            printf("-1\n");//直接退出
            return ;
        }
    printf("%d\n",ans);//输出最少需要通知的人数
    return ;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        update();
        int x,y;
        for(int i=1; i<=m; i++) scanf("%d",&x),p[x]=1;//输入能通知的人 并且p数组相对应的记录下来
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&y);
            for(int j=1; j<=y; j++)
            {
                scanf("%d",&x);
                add(i,x);//构图
            }
        }
        tarjan();
    }
    return 0;
}

There are no shortcuts on the road to success, and perseverance is not a dream.
come on!


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326281159&siteId=291194637