有向图的强连通分量——受欢迎的牛(模板题)

传送门:受欢迎的牛

思路:一个很基本的思路就是,看一个点是否从所有点都能走到它,建立一个反向图,从每一个节点出发做一遍spfa,如果能到达其他的所有节点,说明该节点符合要求。但是这种做法的时间复杂度是是O(n*(n+m)),所以不可取。

改用强连通分量的拓扑图来解决问题:

对于由强连通分量编号形成的拓扑图中,如果有答案的话,那么就一定会有一个点的出度为零,如果有两个点的出度为0的话,因为拓扑图的性质,从其中一个点是无论如何也走不到另一个节点的,所以答案为0.答案不为0则答案就是出度为0的编号的强连通分量里面包含的所有点。

因为强连通分量里面的所有点都是可以互相到达的,而其他分量外的所有点都可以到达这个强连通分量。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int N=1e4+10,M=5e4+10;

int e[M],ne[M],h[N],w[N],idx;
int dfn[N],low[N],times;
int stk[N],top;
bool in_stk[N];
int id[N],scc_cnt,cnt[N];
int dout[N];
int n,m;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++times;
    stk[++top]=u;
    in_stk[u]=true;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }else if(in_stk[j])
        low[u]=min(low[u],dfn[j]);
    }
    if(dfn[u]==low[u])
    {
        ++scc_cnt;
        int y;
        do
        {
            y=stk[top--];
            in_stk[y]=false;
            id[y]=scc_cnt;
            cnt[scc_cnt]++;
        }while(y!=u);
    }
}
int main()
{
     scanf("%d%d",&n,&m);
     memset(h,-1,sizeof h);
     while(m--)
     {
         int a,b;
         scanf("%d%d",&a,&b);
         add(a,b);
     }
     for(int i=1;i<=n;i++)
     if(!dfn[i])
        tarjan(i);

     for(int i=1;i<=n;i++)
        for(int j=h[i];j!=-1;j=ne[j])
     {
         int k=e[j];
         int a=id[i],b=id[k];
         if(a!=b)   dout[a]++;  //记录出度数目
     }
     int sum=0,zero=0;
     for(int i=1;i<=scc_cnt;i++)
        if(!dout[i])  //找到出度为0的点。
     {
         zero++;
         sum+=cnt[i];
         if(zero>1)
         {
             sum=0;
             break;
         }
     }
     printf("%d\n",sum);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值