数据结构——拓扑排序经典例题

定义:
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

步骤:

(1) 选择一个入度为0的顶点并输出;
(2) 从网中删除此顶点及所有出边。

如果输出的顶点数小于输入的顶点数,说明这不是一个拓扑序列,该图存在环。

代码思想:
用vector存入边的信息,设置一个入度的数组,存入度的数量,

topsort函数:
用队列存拓扑序列,先把入度为0的顶点全部入队,取出队列第一个点,输出顶点并把这个顶点的所有出边的入度-1,并判断是不是有新的入度为0的顶点,如果有则入队。直至队列中的所有顶点输出。

例题1:
确定比赛名次
输出一个拓扑序列,并且字典序小的先输出。(此题保证不存在环)

思路:把模板的队列改成优先队列(有小到大)。

#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=510;
vectorvec[maxn];
int du[maxn];
int n,m;

void topsort()
{
	priority_queue,greater > s;
	int flag=0;
	while(!s.empty())
		s.pop();
	for(int i=1;i<=n;i++)
	{
		if(!du[i])
			s.push(i);
	}
	while(!s.empty())
	{
		int now=s.top();
		if(flag==0)
		{
			cout<>n>>m)
	{
		memset(du,0,sizeof(du));
		for(int i=1;i<=n;i++)
			vec[i].clear();
		for(int i=1;i<=m;i++)
		{
			int a,b;
			cin>>a>>b;
			vec[a].push_back(b);
			du[b]++;
		}
		topsort();
		cout<

例题2:只是判断是否存在环

Legal or Not

思路:用拓扑排序就可以判断是否为环。

#include
#include
#include
#include
using namespace std;
const int maxn=110;
int n,m;
vectorvec[maxn];
queues;
int du[maxn];
bool topsort()
{

	int num=0;
	while(!s.empty())	
		s.pop();
	for(int i=0;i>n>>m,n,m)
	{
		memset(du,0,sizeof(du));
		for(int i=0;i>a>>b;
			vec[a].push_back(b);
			du[b]++;
		}
		if(topsort()) cout<<"YES"<

例题3:
Almost Acyclic Graph

给你m条边,不确定有没有环,删除一条边,看是否可以构成有向无环图。

还是判环,我们如果删除每一条边,再进行拓扑排序,时间到了1e7级别,估计会超时。

正解:O(n*m)得到做法,topsort函数不变,记录每一个顶点入度的次数,我们只需要每一次尝试入度大于等于1的顶点-1,尝试一下拓扑排序,因为入度-1,说明其中的某一条边给删掉了,尝试每一个入度>=1的点就可以得到答案。为啥不尝试入度为0的点,因为入度为0的点这条边构不成环,自己可以想想。

#include
#include
#include
#include
using namespace std;
const int maxn=1000;
typedef long long ll;
ll rudeg[maxn],indeg[maxn];//ru为标准 in为操作 
vector vec[maxn];
ll n,m;
int  topsort()
{
	queue q;
	while(!q.empty()) q.pop();
	for(int i=1;i<=n;i++)
	{	
		if(!indeg[i]) 
			q.push(i);
	}
	ll num=0;
	while(!q.empty())
	{
		ll t=q.front();
		q.pop();
		num++;
		for(int i=0;i>n>>m)
	{
		for(int i=0;i<=n;i++)
			vec[i].clear();
		ll flag=0; 
		memset(rudeg,0,sizeof(rudeg));
		memset(indeg,0,sizeof(indeg));
		for(int i=1;i<=m;i++)
		{
			ll a,b;
			cin>>a>>b;
			vec[a].push_back(b);
			indeg[b]++;
			rudeg[b]++; 
		}
		if(topsort())
		{
			flag=1;
		}
		else
		{
			for(int i=1;i<=n;i++)
			{
				for(int i=1;i<=n;i++)
					indeg[i]=rudeg[i];
				if(indeg[i]>=1)
				{
					indeg[i]--;
					if(topsort())
					{
						flag=1;
						break;
					}
				}
			}
		}
		if(flag)
			cout<<"YES"<

例题4:
reward

也是一个拓扑序列,每个人基础888元,a->b 说明a要比b大1(贪心的思想)。
也就是b->a a的层数比b大1层 总金额=前一个金额+1;

#include
#include
#include
#include
using namespace std;
const int maxn=2e4+10;
vectorvec[maxn];
queue q;
int n,m;
int du[maxn],money[maxn],num,sum;

void topsort()
{
	while(!q.empty()) q.pop();
	
	for(int i=1;i<=n;i++)
	{
		if(!du[i])	
		{
			q.push(i);
			money[i]=888;
		}
	}
	
	num=0;
	sum=0;
	while(!q.empty())
	{
		int now=q.front();
		sum+=money[now];
		q.pop();
		num++;
		for(int i=0;i>n>>m)
	{
		memset(du,0,sizeof(du));
		memset(money,0,sizeof(money));
		for(int i=0;i>a>>b;
			vec[b].push_back(a);
			du[a]++;
		}
		
		topsort();
	}
	return 0;
}

你可能感兴趣的:(数据结构,拓扑排序,数据结构)