拓扑排序

基于BFS

定义

给定DAG,若序列A满足,对于图中每条边(x,y),x在A中都出现在y之前,则A为拓扑序,求解A过程为拓扑排序

思想

不断选择图中入度为0的点,然后把to[x]入度–

实现

  1. 建立空序列A
  2. 预处理所有点入度,把入度==0点入队
  3. 取出队头结点x,将x加入序列A
  4. 处理每条边(x,y),–rd[y],若被减为0,y入队
  5. 重复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;
}

原题解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值