拓扑排序,其本质是输出一个全序关系,对于按要求输出给定关系的题目,一般就是按照题目要求实现这个全序关系,这种题时常会先给一个偏序关系,然后给出剩下的元素如何建立关系(字典序之类的)。
如果忘了那几个词是啥意思...
偏序关系:满足自反,反对称,传递性的关系
全序关系:一个偏序关系R,且对任意x,y有xRy或yRx
哈斯图:对一个偏序关系画的图,每个点为关系中的元素,其中,对两点x,y,若有xRy则y画在x上方,若有xRy且不存在s满足xRs,sRy则在x,y中连线。一般情况下把题目里面给的关系直接画出来再分下层就是哈斯图了。和正常的哈斯图不同,为了方便看我们一般会在上面标上箭头。
拿下面这个图说事,按之前的说法,6-2和6-1都在这个偏序关系里面(传递性)但是因为6和1里面连着2就不在他俩连线了,同样对于拓扑排序的题,题目里面说了6-2和2-1以后由传递性就有6-1了,不要拘泥于概念
画上箭头。拓扑排序的效果在于把偏序关系线性输出,在这个里面5,6,7之间没有确定的顺序,还有就是可以按照8-5-6-2这样的顺序,在7之前输出2,没有说同层的必须连着输出。对于这种状况按什么顺序输出是一个考点,经常会把这个顺序根点的标号扯上关系,加上拓扑排序里面用到一个队列,所以时常会在此处把队列操作成优先队列
然后就是拓扑排序可以用于判断有向环,如果在排序中排出来的点比图上的总点数少就说明有有向环。如果一个关系里面出现了环,自然就不满足反对称性了(ex:xRy,yRz,zRx则由传递性有xRz与zRx一起不满足反对称性),然后它就不是一个偏序关系了,所以如果判出来了环的情况论上就不会有下一步操作了。无向环用并查集判断
另外还有的题就是要你确定一个偏序关系,比如统计同样的偏序(可以理解为哈斯图上面同一层的元素)每个有多少
因为拓扑排序这个东西本身比较直观符合大众认知,直接给个裸的拓扑排序显得太亲民,所以如果看见他出现,一般都会是绕了几个弯,变成一道智商题,想直接写一个拓扑排序然后就过了不大现实,搞清楚拓扑排序的思想比较重要,方便在关键时刻能够胡搞的出来。
常用操作:
反向建图:有时会出现=需要把题目所给的偏序反过来的情况,比如下面的2647
把队列换成优先队列
比较纯的拓扑排序,因为要按照字典序输出拓扑序相同的元素,以及时间多,所以可以不使用队列而是暴力遍历
#include <bits/stdc++.h>
using namespace std;
const int maxn=500;
int main()
{
int v,e;
while(cin>>v>>e)
{
vector<int>vec;
vector<int> mp[maxn];
int deg[maxn],s,t;
memset(deg,0,sizeof(deg));
for(int i=1;i<=e;i++)
{
cin>>s>>t;
deg[t]++;
mp[s].push_back(t);
}
for(int i=1;i<=v;i++)
{
for(int j=1;j<=v;j++)
{
if(deg[j]==0)
{
for(int k=0;k<mp[j].size();k++)
{
deg[mp[j][k]]--;
}
deg[j]=INFINITY;
vec.push_back(j);
break;
}
}
}
for(int i=0;i<vec.size()-1;i++)
{
cout<<vec[i]<<" ";
}
cout<<vec[vec.size()-1]<<endl;
}
}