拓扑排序 +队列基础知识+不定数组+优先数列+例题 POJ Genealogical tree

1、什么是拓扑排序

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图
中任 意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序
(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操
作称之为拓扑排序。 无向图和有环的有向图没有拓扑排序拓扑排序其实就是离散上的偏序关系的一个应用
2、拓扑排序的步骤:
1.按照一定的顺序进行构造有向图,记录后个节点的入度; 2,从图中选择一个入度为0的顶点,输出该顶点; 3,从图中
删除该顶点及所有与该顶点相连的边 4,重复上述两步,直至所有顶点输出。 5或者当前图中不存在入度为0的顶点为
止。此时可说明图中有环。 6,因此,也可以通过拓扑排序来判断一个图是否有环。

 

 

拓扑排序模版

#include <bits/stdc++.h>
using namespace std;
int str[10000];//存入度 
vector<int> v[10000];//存关系  构建图 
int main()
{
	int n,m;
	int x,y;
	while(cin>>n>>m)// 根据题目要求可以改动 
	{
		memset(str,0,sizeof(str)); //清空入度 
		for(int i=1;i<=n;i++)  v[i].clear(); //清空vector 
		while(m--) //m组数据 
		{
			cin>>x>>y;
			str[y]++; //x指 y  然后y的入度+1 
			v[x].push_back(y); //让y放在x的后边 
		 } 
		 queue<int> q; //定义一个队列  最后的节点删除 
		 for(int i=1;i<=n;i++)
		 {
		 	if(!str[i]) //开始入度为0的节点放入队列 
		 	{
		 		q.push(i);
			}
		}
		while(!q.empty())
		{
			int xx=q.front();//如果队列中一次存了大于2的节点 
			q.pop();//先把这个点移除对列 
			n--;//总节点数-1 
			for(int i=0;i<v[x].size();i++)//遍历这个节点后面的点 
			{
				int yy=v[xx][i];
				str[yy]--;//删除x后yy的入度就减少1 
				if(!str[yy]) //如果此时yy入度为零放入队列 遍历下一个节点 
				{
					q.push(yy);
				}
			}
		}
		if(n)  cout<<"该图有环"<<endl; //如果总节点数没减为零 说明有环的存在 
	}
	return 0;	
 } 

然后又再次学习几个队列的函数

1. push

2. pop

3. size

4. empty

5. front

6. back

第一个push 函数就是对队列队尾插入一个元素  队列函数的特点是先进先出

1 queue<string> q;
2 q.push("Hello World!");
3 q.push("China");
4 cout<<q.front()<<endl;

就会输出 Hello World 因为这句话先进入队列

第二个pop将函数最前排的元素删去,是没有返回值的void值函数

1 queue<string> q;
2 q.push("Hello World!");
3 q.push("China");
4 q.pop();
5 cout<<q.front()<<endl;

输出的是China  因为第一句话被删除了

第三个是size

返回队列中元素的个数 是unsigned int类型

queue<string> q;
cout<<q.size()<<endl;
q.push("Hello World!");
q.push("China");
cout<<q.size()<<endl;

输出两行 一行是0 没有元素一行是2 俩元素即俩字符串

第四个是empty函数

判断队列是否为空,如果为空返回true

1 queue<string> q;
2 cout<<q.empty()<<endl;
3 q.push("Hello World!");
4 q.push("China");
5 cout<<q.empty()<<endl;

第一次输出1 因为队列中没有元素 第二次输出0 因为队列中有元素

第五个是front

返回值为队列中的第一个元素,也就是最早、最先进入队列的元素。注意这里只是返回最早进入的元素,并没有把它剔除出队列。

1 queue<string> q;
2 q.push("Hello World!");
3 q.push("China");
4 cout<<q.front()<<endl;
5 q.pop();
6 cout<<q.front()<<endl;

输出值为两行,分别是Hello World!和China。只有在使用了pop以后,队列中的最早进入元素才会被剔除

第六个是back

返回队列中最后一个元素,也就是最晚进去的元素。如:

1 queue<string> q;
2 q.push("Hello World!");
3 q.push("China");
4 cout<<q.back()<<endl;

输出值为China,因为它是最后进去的。这里back仅仅是返回最后一个元素,也并没有将该元素从队列剔除掉。

然后是vector函数 这个函数就是行固定列不固定 你加入一个就开一个很方便

 

具体就请见链接https://blog.csdn.net/msdnwolaile/article/details/52708144

火星人的血缘关系制度令人困惑。实际上,火星人在他们想要的时候和他们想要的地方萌芽。他们聚集在一起,不同的群体,所以火星人可以有一个父母和十个。没有人会对一百个孩子感到惊讶。火星人已经习惯了这一点,他们的生活方式似乎很自然。 
在行星理事会中,令人困惑的家谱系统导致了一些尴尬。那里遇到了最有价值的火星人,因此,为了在所有的讨论中冒犯任何人,首先使用它来给老火星人发言,而不是年轻人,而不是最年轻的无子女评估员。但是,维护这个命令确实不是一项微不足道的任务。并不总是火星人知道他的所有父母(并且没有什么可以告诉他的祖父母!)。但如果错误先说出一个孙子而且只是他年轻时出现的曾祖父,这真是一个丑闻。 
你的任务是编写一个程序,该程序将一劳永逸地定义一个命令,该命令将保证安理会的每个成员早于他的每个后代发言。

输入

标准输入的第一行包含唯一的数字N,1 <= N <= 100 - 火星行星理事会的一些成员。根据几个世纪以来的传统,安理会成员的自然数从1到N进行了列举。此外,还有N行,而且,第I行包含了第I个成员的儿童名单。子列表是由空格分隔的任意顺序的子序列号序列。孩子的名单可能是空的。列表(即使它是空的)以0结尾。

产量

标准输出应在其唯一的行中包含一系列扬声器的数字,用空格分隔。如果有几个序列满足问题的条件,那么你要写入标准输出中的任何一个。始终存在至少一个这样的序列。

样本输入

5 
0 
4 5 1 0 
1 0 
5 3 0 
3 0

0 
4 5 1 0 
1 0 
5 3 0 
3 0

样本输出

2 4 5 3 1

这个题的思路就是模版题  然后需要进行一个优先排序 也就是如果两个数字的入度都为0的时候 把数字小的数字排到前边

然后看代码吧

#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
int str[10100];//存入度 
vector<int> v[10100];  //不定数组 
int main()
{
	int n,m,t;
	int x,y;
	cin>>t;
	n=t;
	for(int i=1;i<=t;i++) v[i].clear();  //每次都对不定数组进行清空 
		memset(str,0,sizeof(str));  //每次都对每个点的入度初始化 
		for(int i=1;i<=n;i++){
			while(cin>>x&&x)
			{
				++str[x];
				v[i].push_back(x);  
			}
		}
		priority_queue<int,vector<int>,greater<int> >q;  //快速排序 当两个数字的入度都为0的时候小的排到前边 
		for(int i=1;i<=n;i++)
		{
			if(!str[i]){
				q.push(i);
			}
		 }
		 int flag=1;
		 while(!q.empty())
		 {
		 	int xx=q.top();q.pop();
		 	if(flag)
		 	{
		 		cout<<xx;
		 		flag=0;
			 }
			 else cout<<" "<<xx; //这个输出方式控制最后输出的数字不会有空格 
		 	for(int i=0;i<v[xx].size();i++)
		 	{
		 		int yy=v[xx][i];
		 		str[yy]--;
		 		if(!str[yy]){
		 			q.push(yy);
				 }
			 }
		  }
		  cout<<endl; 
}

优先数列有三种 第一种是正常的排序就是

在优先队列中,优先级高的元素先出队列。

标准库默认使用元素类型的<操作符来确定它们之间的优先级关系。

优先队列的第一种用法,也是最常用的用法:

proiority_queue<int> qi;

通过<操作符可知在整数中元素大的优先级高。

第二种方法 

我们怎么可以把元素从小到大排序呢?

这时我们可以传入一个比较函数。

priority_queue<int,vector<int>,greater<int> > qi2;

其中第二个参数为容器类型。

第二个参数为比较函数。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值