我是什么时候想到要学拓扑排序的呢?
在一次模考的时候,有这样一道题,叫做食物链,我是写了记忆化搜索的,然而全场都写了拓扑板子
后来发现我居然不会这么基础的算法,有点慌
下面进入正题
拓扑排序是针对一些特殊问题的,类似于在完成某一件是之前,有必要条件,要先完成另外的一些任务
只有有向无环图才有拓扑排序,这就关系到了定义
拓扑排序是先排入度为零的点,然后把所有的与之有关的边都删掉,这时就又会有一些如度为零的点出现
然以后循环上述操作
这就是拓扑排序的基本概念
还是举个例子吧
如图:
我们发现1的如度为零
所以先把1删掉,把与1有关的边删掉
然后就发现2的入度变成了零
然后会重复上述操作
得到了这个图的与拓扑排序:1 2 3 4 5
下面给出代码:
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> using namespace std; inline int min(int a,int b){return a<b?a:b;} inline int max(int a,int b){return a>b?a:b;} inline int rd() { int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void write(int x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } int n,m; int head[100006],nxt[100006],to[100006]; int in[100006]; int total=0; void add(int x,int y){//邻接表存边 total++; in[y]++; to[total]=y; nxt[total]=head[x]; head[x]=total; return ; } int tot=0; int s[100006]; void topo(){ for(int i=1;i<=n;i++) if(!in[i]) s[++tot]=i;//先找出已有的入度为零的点 for(int i=1;i<=tot;i++){ for(int e=head[s[i]];e;e=nxt[e]){//删除与其相关的边 in[to[e]]--; if(!in[to[e]]) s[++tot]=to[e];//如果又出现入度为零的点,就入队 } } return ; } int main() { n=rd(),m=rd(); for(int i=1;i<=m;i++){ int x=rd(),y=rd(); add(x,y);//有向图单向存边 } topo(); for(int i=1;i<=n;i++) printf("%d ",s[i]); return 0; }
可算是填了坑QAQ