poj2186我的第一个强连通题目

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#define debug puts("here")

using namespace std;
const int M = 10009;
const int N = 50009;
struct node
{
    int v;
    int next;
}num[N];
int sccf[M];
int low[M];
int dfn[M];
bool ins[M];
int adj[M];
int rdu[M];
int scc, index;

stack<int>s;
int n, m;

void init() {

 scc = 0;
 index = 1;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(adj, -1, sizeof(adj));
memset(ins, false, sizeof(ins));
memset(sccf, 0, sizeof(sccf));

}


void Tarjan(int u) {

   int v;
   low[u] = dfn[u] = index++;
   s.push(u);
   ins[u] = true;
   for(int k = adj[u]; k != -1; k = num[k].next) {

        v = num[k].v;
        if(dfn[v] == 0) {

            Tarjan(v);
            if(low[v] < low[u]) {

                low[u] = low[v];
            }

        }
        else if(ins[v]&& low[v] < low[u]) {

            low[u] = low[v];
        }
   }
   if(low[u] == dfn[u])
   {
       scc++;
       do
       {
           v = s.top();
           s.pop();
           ins[v] = false;
           sccf[v] = scc;//此步进行所谓的缩点;
       }while(u != v);
   }

}
int getsuperpopularnum() {

  memset(rdu, 0, sizeof(rdu));
  int v, u;
  int cnt = 0;
  int cn[N];
  memset(cn, 0, sizeof(cn));
  for(u = 1; u <= n; u++) {

    cn[sccf[u]]++;   //同一缩点内的点数;
    for(int k = adj[u]; k != -1; k = num[k].next)
    {
        v = num[k].v;
        if(sccf[v] != sccf[u])
        {
            rdu[sccf[u]]++;
        }
    }
  }
    for(int i = 1; i <= scc; i++)
    {
        if(rdu[i] == 0)
        {
            cnt++;
            v = i;
        }
    }
    return (cnt == 1)? cn[v] : 0;//如果出度为零的点多以一个, 则无解;
}
int main()
{
   int a, b;
   int e = 0;
   init();
   cin>>n>>m;

   for(int i = 1; i <= m; i++) {

       cin>>a>>b;
       num[e].v = b;  //通过e 找到a 的下一个边b;
       num[e].next = adj[a];//存a可到达的下一个边;
        adj[a] = e;//通过adj[a]找到节点e   
        e++;
   }

   for(int i = 1; i <= n; i++)
   {
       if(dfn[i] == 0)
       {
           Tarjan(i);
       }
   }


  printf("%d\n", getsuperpopularnum());
    return 0;
}
详细资料  :https://www.byvoid.com/blog/scc-tarjan

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值