输出所有可能的拓扑排序

对于一个有向无环图

由某个集合上的一个偏序得到该集合上的一个全序的操作过程称为拓扑排序。

通俗易懂的说就是,想要的到一个有先后顺序的序列。

比如要上课,要先学了一年级的数学,才能学二年级的数学课一样。但学习几年级的语文课,对你要学习数学课没有影响。

想要得到该图的拓扑排序的一种可能,步骤:

(1) 在有向图中选一个没有前驱的顶点且输出之。

(2) 从图中删除该顶点和所有与他连接的边。

重复上述两步,直至全部顶点均已输出,或者当前图不存在无前驱的顶点为止,后一种情况说明有向图中存在环。

 这种方法通过DFS就可以很简单的就得到一个拓扑排序。

那要得到所有可能的拓扑排序要怎么做呢?

可以用DFS+回溯法 来得到

回溯算法在数据结构中是一种常用的算法,也是一种暴力求解法,基本思想,选择一条路一步一步走,当走不通的时候或者已经求得正确的结果,返回上一步,接着选择另一条路走,直到遍历完所有节点。问题的解通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。

这里定义了一个成员变量answer字符串,用来存储得到的答案。

我采用邻接矩阵的存储方式:

下面是拓扑排序的代码,注释超详细。

bool graph::order(int i ,int pos)	//得到的answer是否符合拓扑排序的顺序
{
	for(int j=0; j<pos; j++)		//对answer中顺序检查
	{
		for(int k=0; k<dot_num; k++)		//找到answer【j】对应的点的索引
		{
			if(answer[j]==dot[k])
			{
				if(side[i][k]==1)		//如果answer中出现不符合顺序的两个点,则返回0
				{
					return 0;
				}
			}
		}
	}
	return 1;
}
void graph::topolgical_dfs(int pos)		//拓扑排序专用dfs,第pos-1次递归,当pos+1=点数时,完成一条线路的深度搜索,及拓扑排序递归
{
	if(pos==dot_num)            //搜索到了所有的点
	{
		cout<<answer<<endl;
	}
	else
	{
		for(int i=0; i<dot_num; i++)		//对每个点都进行搜索
		{
			if(tag[i]==0 && order(i,pos))	//该店没被访问,并且第i个点在answer中pos的位置符合拓扑排序
			{
				tag[i]=1;
				answer[pos]=dot[i];
				topolgical_dfs(pos+1);      //从当前点进行下一次搜索
				tag[i]=0;					//可以回溯
			}
		}
	}

}

完整代码,附带很多无效的东西,(为了完成老师的任务)

#include <iostream>
using namespace std;
#define max 100
class graph
{
	public:
		int  dot_num;
		char dot[max];
		bool tag[max];
		int side[max][max];
		int out_d[max],in_d[max];
		string answer;
		graph()
		{
			cout<<"input the number of dot:";
			int n;
			cin>>n;							//输入点的个数
			dot_num=n;
			for(int i=0; i<n; i++)			//加入点
			{
				char dian;
				cout<<"the name of dot(char)"<<i+1<<":";
				cin>>dian;
				answer+=dian;		//初始化answer
				dot[i]=dian;		//设置点
				out_d[i]=0;			//出度设为0
				in_d[i]=0;			//入度设为0
				tag[i]=0;			//标志设为0
				for(int j=0; j<n; j++)
					side[i][j]=0;
			}
			cout<<"input the side(input 0 to end):"<<endl;
			string s;
			while(1)							//加入边,格式:ab(为从点a到点b的边)
			{
				cin>>s;
				if(s=="0")
					break;
				for(int i=0; i<n; i++)
				{
					if(s[0]==dot[i])
					{
						for(int j=0; j<n; j++)
						{
							if(s[1]==dot[j])
							{
								side[i][j]=1;		//边设为1
								out_d[i]=1;			//出度设为0
								in_d[j]=1;			//入度设为1
							}
						}
					}
				}

			}

		}
		void set_tag_0(); 					//全部标志置为0
		void DFS(int pos); 					//深度优先搜索
		bool order(int i ,int j);			//判断拓扑排序是否符合顺序
		void topolgical_dfs(int pos);		//拓扑排序专用DFS
		bool no_loop();						//判断有没有环
		void all_topolgical_sort();			//输出所有拓扑排序
};
void graph::set_tag_0()
{
	for(int i=0; i<dot_num; i++)
		tag[i]=0;
}
void graph::DFS(int pos)					//从dot【pos】开始深度优先遍历
{
	tag[pos]=1;
	for(int j=0; j<dot_num; j++)
	{
		if(side[pos][j]==1)
		{
			if(tag[j]==0)
				DFS(j);
		}
	}
}
bool graph::no_loop()
{
	for(int i=0; i<dot_num; i++)	//每个点都找有没有环
	{
		set_tag_0();
		DFS(i);			//对当前点进行DFS
		for(int j=0; j<dot_num; j++)
		{
			if(side[j][i]==1)		//存在 j 点到 i 点的边 
			{
				if(tag[j]==1)	//并且从 i 点可以访问到 j 点
				{
					return 0;
				}
			}
		}
	}
	return 1;
}
bool graph::order(int i ,int pos)	//是否符合拓扑排序的顺序
{
	for(int j=0; j<pos; j++)		//对answer中顺序检查
	{
		for(int k=0; k<dot_num; k++)		//找到answer【j】对应的点的索引
		{
			if(answer[j]==dot[k])
			{
				if(side[i][k]==1)		//如果answer中出现不符合顺序的两个点,则返回0
				{
					return 0;
				}
			}
		}
	}
	return 1;
}
void graph::topolgical_dfs(int pos)		//第pos-1次递归,当pos+1=点数时,完成一条线路的深度搜索,及拓扑排序递归
{
	if(pos==dot_num)
	{
		cout<<answer<<endl;
	}
	else
	{
		for(int i=0; i<dot_num; i++)		//对每个符合要求的点,访问
		{
			if(tag[i]==0 && order(i,pos))	//没被访问,并且该字母不在字符串中
			{
				tag[i]=1;
				answer[pos]=dot[i];
				topolgical_dfs(pos+1);
				tag[i]=0;					//可以回溯
			}
		}
	}

}
void graph::all_topolgical_sort()
{
	if(no_loop())				//不存在环,才开始找拓扑排序
	{
		set_tag_0();
		topolgical_dfs(0);		//从0开始构造

	}
	else
		cout<<"there is loop in this graph."<<endl;

}
int main(void)
{
	graph mygraph;
	mygraph.all_topolgical_sort();
	return 0;
}

通过输入节点及边创建一个图。当该图有环时,输出有环。

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
拓扑排序是一种对有向无环图(DAG)进行排序的算法。它通过确定顶点的顺序,使得图中的所有边都指向更高顶点。下面是一个用回溯算法实现的拓扑排序的代码片段: bool graph::order(int i, int pos) { for (int j = 0; j < pos; j++) { for (int k = 0; k < dot_num; k++) { if (answer[j] == dot[k]) { if (side[i][k] == 1) { return false; } } } } return true; } void graph::topolgical_dfs(int pos) { if (pos == dot_num) { cout << answer << endl; } else { for (int i = 0; i < dot_num; i++) { if (tag[i] == 0 && order(i, pos)) { tag[i] = 1; answer[pos] = dot[i]; topolgical_dfs(pos + 1); tag[i] = 0; } } } } 这段代码使用了回溯算法来输出所有可能拓扑排序。首先,它定义了一个函数order,用于检查以answer为顺序的顶点是否满足拓扑排序的要求。然后,它定义了一个函数topolgical_dfs,用于进行深度优先搜索并输出所有可能拓扑排序结果。 在topolgical_dfs函数中,首先判断是否已经搜索到了所有的点,如果是,则输出当前的拓扑排序顺序。否则,对每个未被访问的点进行搜索。如果该点在answer中的位置满足拓扑排序的要求,则进行下一次递归搜索。递归结束后,将该点的访问状态回溯,并继续搜索其他未被访问的点。 通过不断地回溯和深度优先搜索,该算法能够输出图中所有可能拓扑排序结果。在搜索过程中,根据题目要求,每次得到一个拓扑排序结果时,将其输出即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值