对有向图的环的判定,并且输出图中所有的路径 C++算法

说明:我们选择的图是有向图,图的存储方式是邻接矩阵,使用C++语言,基于vs2010平台

算法思想:逐个对图中的出度不为0的点进行遍历。假如是先对图A节点进行遍历:首先,将A节点所连接的点存储在数组vect1中,然后对A节点进栈,并对A节点的连接点进行深度优先。当节点的出度为0时,出栈,出栈的时候判断该节点是不是在vec1中的元素,如果是则为环,若不是则不是环。


 代码:

#include<iostream>
#include<vector>
#include<fstream>
using namespace std;

#define N  6
int Mgraph[N][N]={    //邻接矩阵
	{0,1,0,1,0,0},
	{0,0,1,1,1,0},
	{0,0,0,0,0,0},
	{0,0,1,0,0,0},
	{0,0,0,0,0,0},
	{0,0,0,0,0,0}
};

void turn_graph(int Mgraph[][N],vector<vector<int> >&i_graph)
{
	vector<int>temp;
	int i,j;
	for(i=0;i<N;++i)
	{
		temp.clear();
		for(j=0;j<N;++j)
			temp.push_back(Mgraph[i][j]);
		i_graph.push_back(temp);
	}

}

void show_graph(vector<vector<int> >i_graph)
{
	int i,j;
	cout<<"i_graph元素是:"<<endl;
	for(i=0;i<i_graph.size();++i)
	{
		for(j=0;j<i_graph[i].size();++j)
			cout<<i_graph[i][j]<<" ";
		cout<<endl;
	}
}


//void search(int Mgraph[][N],int x)    //在邻接矩阵中搜索从点x开始的路径
void search(vector<vector<int> >i_graph,int x)
{
	int i;
	int size=i_graph.size();        
	vector<int> compare;   //存储点x通向的点
	vector<int> visit;
	vector<int> stack;
	int top=-1;
	compare.clear();
	for(int k1=0;k1<size;++k1)
	{		
		compare.push_back(0);
	}
	for( i=0;i<size;++i)     
	{
		if(i_graph[x][i]==1)    //将点x通向的点,存储到compare中
          compare[i]=1;
	}

	for( i=0;i<size;++i)     //对点x的每个点进行遍历
	{
		//初始化
		visit.clear();
		stack.clear();
		for(int k1=0;k1<size;++k1)     
	    {
		  visit.push_back(0);
		  stack.push_back(0);
	    }
		top=-1;
//		stack.push_back(x);
	    stack[++top]=x;
		visit[x]=1;

		if(i_graph[x][i]==1)    //若有连接
		{
			stack[++top]=i;
			visit[i]=1;
			while(top!=0)    //根节点x不应该出栈
			{
				int k1;
				i=stack[top];
				for( k1=0;k1<size;++k1)
				{
					if(i_graph[i][k1]==1&&!visit[k1])
					{
						stack[++top]=k1;
						visit[k1]=1;
						break;
					}
				}
				if(k1==size)              //若没有与其它节点相连的,就输出stack中所有的元素
				{
					if(top>1)
					{
				  	 for(int k2=0;k2<=top;++k2)
					 {
						 cout<<stack[k2];
					 }
					 if(compare[stack[top]]==1)
						 cout<<"  环"<<endl;
					 else 
						 cout<<endl;
					 }
					 --top;
				}

			}



		}

	}
}


void main()
{
	vector<vector<int> >i_graph; 
	int i=1;
	turn_graph(Mgraph,i_graph);  //将邻接矩阵转移到vector存储的i_graph中
//    show_graph(i_graph);
	cout<<"图中的环以及路径为:"<<endl;
	for(int i=0;i<N;++i)
	{
		search(i_graph,i);
	}
}



由于条件的原因,我需要把数组转换成vector的格式,当然若是提前知道节点数目,用数组会更方便一些。

main函数中,使用一个for循环逐个遍历节点(当节点数目比较多时,为了提高效率,最好只遍历那些有出度的点)。search(i_graph,i)函数在数组中寻找以节点开始的环。

在search(i_graph,i)函数中,先把i所连接的点存储在compare中用于之后判断是不是环。然后对与i相连接的点遍历,先把根节点i进栈,然后使用深度遍历,但是根节点i不出栈。当遍历的节点没有出度时,将栈中除根节点的节点出栈,并且判断top节点是否在compare中,若在则是环,若不在则不是环。


结果:





  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
邻接表表示的有向图可以通过深度优先搜索(DFS)算法判定是否为有向无图(DAG)。具体算法步骤如下: 1. 对每个节点维护三个状态:未访问(0)、正在访问(1)、已访问(2)。 2. 从任意一个未访问的节点开始深度优先遍历,每次遍历到一个节点时,将其状态设置为正在访问。 3. 对于当前节点的每个邻接节点,如果其状态是未访问,则对其进行递归访问。 4. 如果当前节点的任意邻接节点状态为正在访问,说明存在,直接返回false。 5. 遍历完所有邻接节点后,将当前节点状态设置为已访问,返回true。 下面是具体的C++代码实现: ```c++ #include <iostream> #include <vector> using namespace std; bool dfs(vector<vector<int>>& graph, vector<int>& visited, int cur) { visited[cur] = 1; // 当前节点状态设置为正在访问 for (int next : graph[cur]) { if (visited[next] == 0) { // 邻接节点未访问,递归访问 if (!dfs(graph, visited, next)) { return false; } } else if (visited[next] == 1) { // 存在,返回false return false; } } visited[cur] = 2; // 当前节点状态设置为已访问 return true; } bool isDAG(vector<vector<int>>& graph) { int n = graph.size(); vector<int> visited(n, 0); // 初始化所有节点状态为未访问 for (int i = 0; i < n; i++) { // 从任意一个未访问的节点开始遍历 if (visited[i] == 0) { if (!dfs(graph, visited, i)) { return false; } } } return true; } int main() { vector<vector<int>> graph = {{1, 2}, {3}, {3}, {4, 5}, {5}, {}}; if (isDAG(graph)) { cout << "The graph is a DAG." << endl; } else { cout << "The graph is not a DAG." << endl; } return 0; } ``` 上面的代码,`graph`是邻接表表示的有向图,`visited`是节点状态数组。`dfs`函数是深度优先遍历函数,`isDAG`函数则是判断有向图是否为DAG的函数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一杯拿铁go

你的打赏是我更新最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值