基于BFS
定义
给定DAG,若序列A满足,对于图中每条边(x,y),x在A中都出现在y之前,则A为拓扑序,求解A过程为拓扑排序
思想
不断选择图中入度为0的点,然后把to[x]入度–
实现
- 建立空序列A
- 预处理所有点入度,把入度==0点入队
- 取出队头结点x,将x加入序列A
- 处理每条边(x,y),–rd[y],若被减为0,y入队
- 重复3.4.到队列为空
以上from《算法竞赛进阶指南》
用处
点之间有严格层次(DP可用)
代码(板子)
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int next[N],first[N],to[N],rd[N],a[N],tot,n,cnt=0,m;
void add(int x,int y){
next[++tot]=first[x];
first[x]=tot;
to[tot]=y;
rd[y]++;//rd入度
}
void topsort(){
queue<int> q;
for(int i=1;i<=n;i++){
if(rd[i]==0){
q.push(i);
}
}
while(q.size()){
int x=q.front();q.pop();
a[++cnt]=x;
for(int i=first[x];i;i=next[i]){
int y=to[i];
if(--rd[y]==0){
q.push(y);
}
}
}
}
int main(){
scanf("%d%d",&n,&m);//n点数m边数
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
topsort();
for(int i=1;i<=cnt;i++){
printf("%d ",a[i]);
}
return 0;
}
拓扑排序例题(拓扑+并查集)
P2419 [USACO08JAN]牛大赛Cow Contest
题解
并查集:如果是两个图肯定不行(直接看成一块一块的,两个图之间肯定没法比较)
拓扑排序 拓扑的妙用来啦 :根据这两点是否连通拓扑,保证按照顺序来走
#include <bits/stdc++.h>
#define N 105
using namespace std;
int fa[N],rd[N],Map[N][N],path[N][N],n,m;
int find_(int x) {return x==fa[x]?x:fa[x]=find_(fa[x]);}
int topo()
{
int ret=0,que[N<<4],l=0,r=0;
for(int i=1;i<=n;++i) if(!rd[i]) que[++r]=i;
for(int now;l<r;)
{
now=que[++l];
if(l==r)
{
int i=1;
for(i=1;i<=r;++i) if(path[now][que[i]]==0) break;
if(i==r+1) ret++;
}
for(int i=1;i<=n;++i)
if(Map[now][i])//这两个点可走通
{
if(rd[i])
{
rd[i]--;
if(!rd[i]) que[++r]=i;
for(int j=1;j<=r;++j) path[i][que[j]]|=path[now][que[j]];//==if(path[now][que[j]]) path[i][que[j]]=1;
//现在枚举到的点和队列里现在枚举到的点连通,由两两可连通,i与que[j]也可连通
}
}
}
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for(int x,y,i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
fa[find_(y)]=find_(x);
rd[y]++;
Map[x][y]=1;
}
int k=0;
for(int i=1;i<=n;++i) {if(fa[i]==i) k++;path[i][i]=1;} //fa[i]==i,是连通块 (看成无向图) ,每个点都在一个图中
if(k>1) printf("0\n");
else printf("%d\n",topo());
return 0;
}