Tarjan算法
一个图是否连通可以通过tarjan算法搞定。
结点
public class vertexNode {
/*
* 边的链式存储
* */
public int v; //起点
public int next; //终点
}
java实现算法,垃圾代码…
package alo_Graph;
public class Graph_Tarjan {
static int cnt;
static int tot;
static int index,m=0,k=1;
/******************************************tarjan算法-***********************************************/
//比较两个数返回较小值
static int min(int a,int b) {
return a>b?b:a;
}
//边的插入操作
static void add(G g,int x,int y){
g.EG1[++cnt] = new vertexNode();
g.EG1[cnt].next=g.heads[x];
g.EG1[cnt].v = y;
g.heads[x]=cnt;
}
//代表第几个点在处理。递归的是点。
static void tarjan(G g,int x){
g.DFN[x]=g.LOW[x]=++tot; //新进点的初始化
g.stack[++index]=x; //进站
g.visit[x]=1; //表示在栈里
for(int i=g.heads[x];i!=-1;i=g.EG1[i].next){
if(g.DFN[g.EG1[i].v]==0) { //如果没访问过
tarjan(g,g.EG1[i].v); //往下进行延伸,开始递归
g.LOW[x]=min(g.LOW[x],g.LOW[g.EG1[i].v]); //递归出来,比较谁是谁的儿子/父亲(树的对应关系)
}else if(g.visit[g.EG1[i].v]==1){ //如果访问过,并且还在栈里。
g.LOW[x]=min(g.LOW[x],g.DFN[g.EG1[i].v]); //比较谁是谁的儿子/父亲(链接对应关系)
}
}
//发现是整个强连通分量子树里的最小根。
if(g.LOW[x]==g.DFN[x]){
do{
System.out.print(g.stack[index]+"-"); //打印输出连通子图
g.pr[m][g.stack[index]] = k;
g.visit[g.stack[index]]=0;
index--;
}while(x!=g.stack[index+1]);//出栈,并且输出。
g.number++;m++;k++;
System.out.println();
}
}
//打印tarjan算法结果 给出连通图的个数
public static String print_tarjan(G g) {
String temp = "";int z=1; //记录连通子图数量
if(g.number == 1) {
temp+="<";
for(int n1=0;n1<g.vernum;n1++) {
temp+=g.vertexes[n1].data+" ";
}
temp+=">";
//number为1表示只有1个连通区域
}else {
for(int n=0;n<g.number;n++) {
temp+="<";
for(int n1=0;n1<g.vernum;n1++){
if(g.pr[n][n1]==z) {
temp+=g.vertexes[n1].data+" ";
}
}
z++;
temp+=">\r\n";
}
}
return temp;
}
//tarjan连通性算法的主方法 外部调用该方法实现图的强连通性判断 划分连通子图
public static void tarjan_main(G g){
cnt=0;
tot=0;
index=0;m=0;k=1;
g.DFN = new int[g.MAX_N]; //初始化各个数组
g.LOW = new int[g.MAX_N];
g.stack = new int[g.MAX_N];
g.heads = new int[g.MAX_N];
g.pr = new int[10][g.MAX_N];
g.visit = new int[g.MAX_N];
int i;g.number=0;m=0;k=1; //初始化各变量
for(i=0;i<g.MAX_N;i++){
g.heads[i] = -1;
g.DFN[i] = 0;
g.LOW[i] = 0;
g.visit[i] = 0;
}
for(i=0;i<10;i++) { //初始化二维连通分布数组
for(int j=0;j<g.MAX_N;j++){
g.pr[i][j] = 0;
}
}
g.EG1 = null;
g.EG1 = new vertexNode[g.MAX_N];//初始化图的边的集合
for(i=0;i<g.arcnum;i++){
add(g,g.EG[i].u,g.EG[i].v);
add(g,g.EG[i].v,g.EG[i].u);
}
for(i=1;i<g.vernum;i++)
if(g.DFN[i]==0)tarjan(g,i);//当这个点没有访问过,就从此点开始。防止图没走完
}
}
大神C++版本
#include <iostream>
#include <string.h>
using namespace std;
const int MAX_N=10000;
struct edge
{
int to,next;
}e[MAX_N];
int p[MAX_N],eid;
void init()
{
eid=0;
memset(p,-1,sizeof(p));
}
void insert(int u,int v)
{
e[eid].to=v;
e[eid].next=p[u];
p[u]=eid++;
}
int dfn[MAX_N],low[MAX_N]; //当前时间戳,最早次序号,dfn只能初始化为0!
int idx=0; //时间戳初始化为0
int belong[MAX_N],scc=0; //belong记录每个顶点属于哪个强连通分量,scc为强连通分量总数
int s[MAX_N],top=0; //模拟栈
bool instack[MAX_N]; //是否在栈中
void tarjan(int u)
{
dfn[u]=low[u]=++idx;
s[top++]=u;
instack[u]=true;
for(int i=p[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
++scc;
do
{
belong[s[--top]]=scc;
instack[s[top]]=false;
}
while(s[top]!=u);
}
}
int main()
{
init();
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
insert(a,b);
}
// tarjan(0);
for(int i=1;i<=n;i++) //用这种方法更新全部点
if(dfn[i]==0)
tarjan(i);
for(int i=1;i<=n;i++)
cout<<i<<"->"<<belong[i]<<endl;
return 0;
}