求解强连通分量的一种方法

18 篇文章 0 订阅

如果对于任意两个不同的顶点u和v,存在一个从u到v的有向路径以及从v到u的有向路径,这样的有向图被称为是强连通的。一般来说,一个有向图的顶点可以分割成一些互不相交的最大子集,每个子集的顶点之间可以通过有向图中的有向路径相互访问,这些子集被称为强连通分量。
下面的方法来自《算法设计与分析基础》作者: Anany Levitin 译者: 潘彦

下面三步说的顶点变成死端是递归的dfs出栈的顺序。

第一步:对给定的有向图执行一次DFS遍历,然后按照顶点变成死端的顺序对它们进行编号。
第二步:颠倒有向图所有边方向。
第三步:对于新的有向图,从仍未访问过的顶点中编号最大的顶点开始(而且如果有必要的话,可以重新开始)做一遍DFS遍历。

邻接表

package d;



public class AGraph {
int n,e;
VNode adjlist[];
public AGraph(int n) {
	super();
	this.n = n;
	adjlist=new VNode[n];
}

}

package d;

class ArcNode{

int adjvex;  ArcNode nextarc;

ArcNode reverse_nextarc;




public ArcNode() {

}

 

public ArcNode (int adjvex){

this.adjvex=adjvex;

};

}


package d;

class VNode{//邻接矩阵的顶点也可以用这个

ArcNode firstarc;

ArcNode reverse_firstarc;

int Serial_number;//DFS访问后按照死端编号
char info;
 

public VNode(char info) {

this.info = info;

}



public VNode() {
	super();
}
}

主程序

package d;


import java.util.Comparator;

class Mycomparator implements Comparator<VNode>
{
	public int compare(VNode v1,VNode v2)
	{
		int a=v1.Serial_number;
		int b=v2.Serial_number;
		if (a>b)
		{
			return -1;//按照这种方式排序
		}
		else if (a<b)
		{
			return 1;
		}
		return 0;
	}
}


















public class Main {
	public static int top=-1;
	public static int[]stack;
	
//正常的DFS	
	public static void DFS1(AGraph a)
	{	//-1表示未访问,-2表示是起始节点(前面没东西)
		stack=new int[a.n];
		int visited[]=new int[a.n];
		for(int i=0;i<a.n;i++)//如果要求路径的话
			visited[i]=-1;//visited设为-1
		for(int i=0;i<a.n;i++)
			if(visited[i]==-1)//这里也改为-1
			dfs3(a,i,visited,-2);//-2表示是起始节点
	}
	
	
	
	
	
	
	public static void dfs3(AGraph a,int start,int visited[],int before)
	{
	//visited必须初始化为-1,不然初始化为0
	//分不清visited==0是没有被访问还是被访问了前面一个是0
	visited[start]=before;
	//进栈操作(按照课本上那种进栈顺序)
	ArcNode arc=a.adjlist[start].firstarc;
	while(arc!=null)
	{	if(visited[arc.adjvex]==-1)
		{
			dfs3(a,arc.adjvex,visited,start);}
			arc=arc.nextarc;
	}
	a.adjlist[start].Serial_number=++top;
	stack[top]=start;
	}
	
	

	
	
	
//反向邻接表的DFS:
	public static void reverse_DFS1(AGraph a)
	{	//-1表示未访问,-2表示是起始节点(前面没东西)
		int visited[]=new int[a.n];
		for(int i=0;i<a.n;i++)//如果要求路径的话
			visited[i]=-1;//visited设为-1
		while(top!=-1)
		{	
			int i=stack[top--];
			if(visited[i]==-1)//这里也改为-1
			{
				System.out.print("当前强连通分量为:");
				reverse_dfs3(a,i,visited,-2);//-2表示是起始节点
				System.out.println();
			}
		}	
	}
	
	
	
	public static void reverse_dfs3(AGraph a,int start,int visited[],int before)
	{
	//visited必须初始化为-1,不然初始化为0
	//分不清visited==0是没有被访问还是被访问了前面一个是0
	visited[start]=before;
	System.out.print(a.adjlist[start].info+" ");
	
	ArcNode arc=a.adjlist[start].reverse_firstarc;
	while(arc!=null)
	{	if(visited[arc.adjvex]==-1)
		{
			reverse_dfs3(a,arc.adjvex,visited,start);
		}
			arc=arc.reverse_nextarc;
	}
	
	}
	
	
	
	
	public static void reverse(AGraph a)
	
		{//颠倒有向图的方向,作反向邻接表
	
		ArcNode [] temp=new ArcNode[a.n];//第i个反向时   现在对应的ArcNode
	
		
	
		 
	
		 
	
		for(int i=0;i<a.n;i++)
	
		{
	
		ArcNode arc=a.adjlist[i].firstarc;
	
		while(arc!=null)
	
		{
	
			if(temp[arc.adjvex]==null)
		
			{
		
			a.adjlist[arc.adjvex].reverse_firstarc=new ArcNode(i);
		
			temp[arc.adjvex]=a.adjlist[arc.adjvex].reverse_firstarc;
		
			}
		
			else
		
			{
			temp[arc.adjvex].reverse_nextarc=new ArcNode(i);
			temp[arc.adjvex]=temp[arc.adjvex].reverse_nextarc;
		
			
		
			}
		
			arc=arc.nextarc;
		
		}
	
		 
	
		 
	
		}
		}
	
	public static void main(String[] args) {
		AGraph a=new AGraph(8);
		for(int i=0;i<a.n;i++)
			a.adjlist[i]=new VNode((char)('a'+i));
		

		ArcNode arc;


		a.adjlist[0].firstarc=new ArcNode(1);

		 

		 

		a.adjlist[1].firstarc=new ArcNode(6);

		


		a.adjlist[2].firstarc=new ArcNode(3);
		a.adjlist[2].firstarc.nextarc=new ArcNode(4);
	

		a.adjlist[3].firstarc=new ArcNode(1);
		a.adjlist[3].firstarc.nextarc=new ArcNode(6);
		

		 

		a.adjlist[4].firstarc=new ArcNode(7);

		

		a.adjlist[5].firstarc=new ArcNode(0);
		a.adjlist[5].firstarc.nextarc=new ArcNode(1);

		 

		 

		a.adjlist[6].firstarc=new ArcNode(5);
		
		
		a.adjlist[7].firstarc=new ArcNode(2);
		a.adjlist[7].firstarc.nextarc=new ArcNode(3);
		
		
		DFS1(a);
		System.out.println();
		/*不能排序的,一排序就会改变数组的顺序
		Comparator<VNode> cmp=new Mycomparator();
		Arrays.sort(a.adjlist,cmp);
		for (int i=0;i<a.n;i++)
		{
			System.out.print(a.adjlist[i].info+" ");
		}
		*/
		
		//直接用stack出栈就行就行
		
		
		
		reverse(a);
		
		
/*		ArcNode arcc;
		for(int i=0;i<a.n;i++)
		{	System.out.print(i);
			arcc=a.adjlist[i].reverse_firstarc;
			while(arcc!=null)
			{
				System.out.print(arcc.adjvex);
				arcc=arcc.reverse_nextarc;
			}
			System.out.println();
		}*/
		
		
			
		reverse_DFS1(a);
		
		
			
		
		

	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值