强连通(当模板用)——pku2186Popular Cows

有向图强连通分量的Tarjan算法

有个比较好的讲解http://www.byvoid.com/blog/scc-tarjan/zh-hans/

学习一下,贴个比较好的模板

View Code
#include <iostream>
#include
<stack>
using namespace std;

const int MAXN = 10000 + 10; // 点的最大数量
const int MAXM = 50000 + 10; // 边的最大数量

// 假设对边u-->v
struct EDGE
{
int v; // 从u点出发能到达的点v
int next; // 从u点出发能到达的下一条边的编号
};

stack
<int> s;
EDGE map[MAXM];
int low[MAXN]; // low[u]:是u或u的子树能够追溯到的最早的栈中节点的次序号
int dfn[MAXN]; // dfn[u]:节点u搜索的次序编号(时间戳)
int pre[MAXN]; // pre[u] = e:从点u出发的最后一条边的编号是e(“最后”是指最后输入)
int sccf[MAXN]; // sccf[i] = j:第i个点所在的强连通分量的编号
bool ins[MAXN]; // 是否在栈中
int outdegree[MAXN]; // 强连通分量的出度
int index; // 次序编号
int scc; // 强连通分量的数目
int n, m;

void Tarjan(int u)
{
int v;
low[u]
= dfn[u] = index++;
s.push(u);
ins[u]
= true;
// 枚举每一条边:u-->v
for (int k=pre[u]; k!=-1; k=map[k].next)
{
v
= map[k].v;
if (dfn[v] == 0)
{
Tarjan(v);
if (low[v] < low[u])
{
low[u]
= low[v];
}
}
else if (ins[v] && dfn[v]<low[u])
{
low[u]
= dfn[v];
}
}
// 如果节点u是强连通分量的根
if (dfn[u] == low[u])
{
scc
++;
do
{
v
= s.top();
s.pop();
ins[v]
= false;
sccf[v]
= scc;//这里就是一个缩点的过程
}while (u != v);
}
}

void Init()
{
scc
= 0;
index
= 1;
memset(low,
0, sizeof(low));
memset(dfn,
0, sizeof(dfn));
memset(ins,
false, sizeof(ins));
memset(sccf,
0, sizeof(sccf));
memset(pre,
-1, sizeof(pre));
}

// 获得超级受喜欢的cows的数量
int GetSuperPopularNum()
{
int u, v;
int cnt = 0; // 出度为0的强连通分量的数目
int ct[MAXN]; // ct[i] = j:强连通分量i有j个点

memset(outdegree,
0, sizeof(outdegree));
memset(ct,
0, sizeof(ct));

// 枚举每一个点u:求outdegree和ct
for (u=1; u<=n; u++)
{
ct[sccf[u]]
++;
for (int k=pre[u]; k!=-1; k=map[k].next)
{
// 对每条边u-->v
v = map[k].v;
if (sccf[u] != sccf[v])
{
outdegree[sccf[u]]
++;
}
}
}
// 数数强连通分量为0的点有多少个
for (u=1; u<=scc; u++)
{
if (outdegree[u] == 0)
{
cnt
++;
v
= u;
}
}
return (cnt == 1)? ct[v] : 0;
}

int main()
{
int i, u, v;
int e = 0; // 边的数量,建图时会用到
// 初始化数据并建图
Init();
//cin >> n >> m;
scanf("%d%d",&n,&m);
for (i=0; i<m; i++)
{
//cin >> u >> v;
scanf("%d%d",&u,&v);
map[e].v
= v;
map[e].next
= pre[u];
pre[u]
= e;
e
++;
}
// 求强连通分量
for (i=1; i<=n; i++)
{
if (dfn[i] == 0)
{
Tarjan(i);
}
}
// 输出答案
cout << GetSuperPopularNum() << endl;
return 0;
}

  

原文地址:https://www.cnblogs.com/huhuuu/p/2121148.html