图论——拓扑排序

本文介绍了如何进行拓扑排序,重点在于理解在无环有向图(DAG)中如何找到入度为0的起点,并通过遍历更新其它节点的入度。同时,讨论了在有环图中检测环的方法以及当所有点两两间都有关系时的特殊情况。并提供了洛谷P1347排序问题的背景和分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拓扑排序的构建

到目前为止,我只会从度的方面来构造拓扑,而用dfs或者sort来构建我还没学会
拓扑排序是存在在DAG中,而在DAG中因为是无环的,所以必然存在一个点v1他是入度为0的,那么这个入度为0的点就是当前的出发点。
在这里插入图片描述
然后遍历v1的周边的点v2,v3,然后他们的入度个数减去1,这时候会出现两个入度为0的点,然后压入队列(栈),重复操作。

但是拓扑排序有几个特殊情况:

  1. 如果说这个是个有环的图,那么就在上述操作过程中,一定会出现没有遍历完所有的点就结束操作的情况,那么这个时候我们就可以根据遍历的点和它总共的点的个数来判断是否有环。(这个包括了自己指向自己的情况)
  2. 如果说题目中说每个点之间都有关系,那么注意在一次中只会出现一个入度为0的点,否则就不可能两两之间的都有明确的关系。

题目

洛谷P1347 排序

传送门
题解
这道题因为她要求求在第几个关系前确定关系,所以每次我们输入一个关系那么我们就要检验一遍拓扑。

#include<iostream>
#include<string>
#include<queue>
#include<vector>
#include<cstdio>
using namespace std;
int g[26][26];//字母间的大小关系
int r[26];//字母的入度的个数
int vis[26];//是否有输入这个字母
queue<int> q;
int order[26];//存最后拓扑序列
int n, m;
int sum = 0, sum1 = 0;
int topo()
{
	int ru[26], v = 0, flag = 0;//flag检验环 ,ru也是暂时的入度个数,因为要多次拓扑,为了不影响后面操作,v存当时入度为0 的点的个数
	sum = 0;	
	for(int i = 0; i < n; i++)
	{
		ru[i] = r[i];		
		if(!ru[i] && vis[i])//vis很重要,有些字母没输入当然不在图中
		{
			if(v) flag = 1;
			else v = 1;
			q.push(i);
			order[sum++] = i;
		}
	}
	if(q.empty()) return 1;//如果没有度为0 的点,说明是有环
	while(!q.empty())
	{
		int u = q.front();
		q.pop();
		v = 0;
		for(int i = 0; i < 26; i++)
		{
			if(g[u][i])
			{
				ru[i]--;
				if(!ru[i])
				{//cout <<u << ' ' <<  i << endl;
					if(v)  flag = 1;
					else v = 1;
					q.push(i);
					order[sum++] = i;
				}				
			}
		}
	}//cout << sum1 << sum << endl;
	if(sum1 != sum)
		return 1;
	else if(flag)
		return 2;
	else
		return 0;
} 
int main()
{	
	string str;
	cin >> n >> m;
	for(int i = 1; i <= m; i++)
	{
		cin >> str;	
		if(g[str[0]-'A'][str[2]-'A'] == 0)//题目会出现重复的边,为了不让一个点的入度不多加
		{
			g[str[0]-'A'][str[2]-'A'] = 1;
			r[str[2]-'A']++;	
		}	
		
		 
		if(!vis[str[0]-'A']) 
		{
			sum1++;
			vis[str[0]-'A'] = 1;
		};
		if(!vis[str[2]-'A']) 
		{
			sum1++;
			vis[str[2]-'A'] = 1;
		};
		int flag = topo();
		if(flag == 1) 
		{
			printf("Inconsistency found after %d relations.", i) ;
			return 0;
		}
		else if(flag == 0 && sum == n)//已经有了n个不同的数
		{
			printf("Sorted sequence determined after %d relations: ", i);
			for(int i = 0; i < sum; i++)
				printf("%c", order[i]+'A');
			cout << ".";
			return 0;	
		}			
	} 
	cout << "Sorted sequence cannot be determined." << endl;
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值