您的位置:首页 > 其它

tarjan 强连通 模板

2016-07-27 15:20 253 查看
2SAT中的重要知识 以前学过忘记存了。现在存一发免得再忘了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <cmath>
#include <map>
#include <string>
#include <stack>
#include <queue>

using namespace std;
const int MAXN=1e5+10;
struct node
{
int v;
int nxt;
};
node edge[MAXN];//边数
int head[MAXN];
int n,m;
int Stop,Bcnt,Dindex;//栈头,强通块数,时间戳
int DFN[MAXN],LOW[MAXN];//首时间戳,最近回溯点(根)
int Stap[MAXN];//答案栈
int instack[MAXN];//是否在栈中
int Belong[MAXN];//这个点属于第几个强连通块(点)
int cnt=0;
void add_edge(int u,int v)
{
edge[cnt].v=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
cnt++;
}
void tarjan(int i)
{
int j;
DFN[i]=LOW[i]=++Dindex;
instack[i]=1;
Stap[++Stop]=i;
for (int e=head[i]; e!=-1; e=edge[e].nxt)
{
j=edge[e].v;
if (!DFN[j])//儿子没遍历
{
tarjan(j);//遍历
if (LOW[j]<LOW[i])//如果儿子已经形成环
LOW[i]=LOW[j];//父亲也要在回溯的时候进入环
}
else if (instack[j]&&DFN[j]<LOW[i])//邻接的在栈里,所以是大大
LOW[i]=DFN[j];//把这个点归到大大那
}
if (DFN[i]==LOW[i])//这个点的根是自己
{
Bcnt++;//多了一个强连通分量
do
{
j=Stap[Stop--];//退栈
instack[j]=0;//标记
Belong[j]=Bcnt;//标记
}
while (j!=i);
}
}
void solve()
{
int i;
Stop=Bcnt=Dindex=0;//栈头,强通块数,时间戳
memset(DFN,0,sizeof(DFN));
for (int i=1; i<=n; i++)
if (!DFN[i])
tarjan(i);
}
int main()
{
while (scanf ("%d%d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));
while (m--)
{
int t1,t2;
scanf ("%d%d",&t1,&t2);
add_edge(t1,t2);
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: