拓扑排序板子练习

目录

一、前言

二、拓扑排序板子

三、题目:拓扑顺序

1、上链接

2、基本思路

3、代码

(1)C++(AC)

(2)python(AC)

四、题目:可达性统计

1、上链接

2、基本思路

3、代码

(1)C++(AC)

(2)python


一、前言

拓扑排序想必不用再多介绍了,下面来看看拓扑排序的一个板子(遍历某一个点的所有边),并做两道拓扑排序相关的例题。

二、拓扑排序板子

直接看代码。

#include<iostream>
#include<queue>   // 拓扑排序经常需要用到队列 
#include<cstring>
using namespace std;

const int N=10010;
int n,m; //顶点数,边数 
int e[N],h[N],ne[N],idx;  //某边终点、以某点为起点的第一条边、以某点为起点的下一条边、第idx条边 
int degree[N];  //存储对应点的入度 

void Add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void topsort(){
	queue<int> q;
	for(int i=1;i<=n;++i)
		if(!degree[i])
			q.push(i);
									
	while(!q.empty()){
		int t=q.front();
		q.pop();
		cout<<t<<" ";
		
		for(int i=h[t];~i;i=ne[i]){
			int j=e[i];
			if(--degree[j]==0)
				q.push(j);
		}
	}
	cout<<endl;
}

int main(){
	
	cin>>n>>m;
	
	memset(h,-1,sizeof h);  //所以~i能结束
	
	for(int i=0;i<m;++i){
		int a,b;
		cin>>a>>b;
		Add(a,b);  //把当前的边存起来 
		degree[b]++;
	}
	
	topsort();
	
	return 0;
	
}
 

三、题目:拓扑顺序

1、上链接

1639. 拓扑顺序 - AcWing题库

2、基本思路

对拓扑排序的板子进行相应的修改即可。

3、代码

(1)C++(AC)

#include<iostream>
#include<queue>   // 拓扑排序经常需要用到队列 
#include<cstring>
using namespace std;

const int N=10010;
const int K=110;
int n,m,k; //顶点数,边数 
int e[N],h[N],ne[N],idx;  //某边终点、以某点为起点的第一条边、以某点为起点的下一条边、第idx条边 
int degree[N];  //存储对应点的入度 
int ask[N],flg[K],d[N];

void Add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

int topsort(){
	for(int i=1;i<=n;++i){
		if(d[ask[i]])
			return 0;
		
		for(int j=h[ask[i]];~j;j=ne[j]){
			d[e[j]]--;
		}
	}
	return 1;
}

int main(){
	
	cin>>n>>m;
	
	memset(h,-1,sizeof h);
	
	for(int i=0;i<m;++i){
		int a,b;
		cin>>a>>b;
		Add(a,b);  //把当前的边存起来 
		degree[b]++;
	}
	
	cin>>k;
	
	for(int i=0;i<k;i++){
		for(int j=1;j<=n;j++){
			cin>>ask[j];
			d[ask[j]]=degree[ask[j]];
			//或这样写,都是一样的  
			// d[j] = degree[j]
		}
		if(topsort())
			flg[i]=1;
		else
			flg[i]=0;
	}
	
	int i=0;
	for(i=0;i<k;i++){
		if(!flg[i]){
			cout<<i;
			break;
		}
	} 
	
	i++;
	for(;i<k;++i){
		if(!flg[i])
			cout<<" "<<i;
	}
	cout<<endl;
	
	return 0;	
}
 

(2)python(AC)

N=10010

e=[0]*N
ne=[0]*N
h=[-1]*N
idx=0

degree=[0]*N
d=[0]*N
ask=[0]*N
flg=[0]*110

def Add(a,b):
    global idx
    e[idx]=b
    ne[idx]=h[a]
    h[a]=idx
    idx=idx+1

def topsort():
    for i in range(1,n+1):
        if d[ask[i]]!=0:
            return 0
        j=h[ask[i]]
        while ~j:
            d[e[j]]-=1
            j=ne[j]
    return 1


n,m=map(int,input().split())

for i in range(m):
    a,b=map(int,input().split())
    Add(a,b)
    degree[b]+=1

k=int(input())

for i in range(k):
    lines=list(map(int,input().split()))
    for j in range(1,n+1):
        ask[j]=lines[j-1]
        d[ask[j]]=degree[ask[j]]
    if topsort():
        flg[i]=1
    else:
        flg[i]=0
##    print(flg[i],end="@")
##    print("")
        

c=0
for i in range(k):
    if c==0 and flg[i]==0:
        print(i,end="")
        c=1
    elif flg[i]==0:
        print(" {}".format(i),end="")
print("")


四、题目:可达性统计

1、上链接

164. 可达性统计 - AcWing题库

2、基本思路

对拓扑排序的板子进行相应的修改即可。

3、代码

(1)C++(AC)

#include<iostream>
#include<cstring>
#include<queue>
#include<bitset>
using namespace std;

const int N=30010;
int n,m;
int e[N],ne[N],h[N],idx;
int degree[N];
int seq[N];

bitset<N> f[N];

void Add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void topsort(){
	queue<int> q;
	for(int i=1;i<=n;++i)
		if(degree[i]==0)
			q.push(i);
			
	int k=0;
	while(!q.empty()){
		int t=q.front();
		q.pop();
		
		seq[k++]=t;
		for(int i=h[t];~i;i=ne[i]){
			int j=e[i];
			if(--degree[j]==0)
				q.push(j);
		}
	}
}

int main(){
	cin>>n>>m;
	memset(h,-1,sizeof h);
	for(int i=0;i<m;i++){
		int a,b;
		cin>>a>>b;
		Add(a,b);
		degree[b]++;
	}
	
	topsort();
	
	for(int i=n-1;i>=0;i--){
		int j=seq[i];
		f[j][j]=1;
		for(int p=h[j];~p;p=ne[p]){
			f[j]|=f[e[p]];
		}
	}
	
	for(int i=1;i<=n;++i){
		cout<<f[i].count()<<endl;
	}
	
	return 0;
} 

bitset用来处理二进制位非常方便。头文件是 #include<bitset>,bitset可能在PAT、蓝桥OJ中不常用,但是在LeetCode OJ中经常用到~而且知道 bitset 能简化一些操作,可能一些复杂的问题能够直接用 bitset 就很轻易的解决了。

bitset的用法随便百度一下就能找到一大堆,这里就不啰嗦了。

解释一下为什么“ f[j] |= f[e[p]] ”,如下图。(所以序列的遍历方向从后往前)

(2)python

我也想写一个python代码,在python中,bitset也确实可以写成一个类来实现,但是这个“类bitset”并不能起到优化空间的作用,该到题的内存会爆。而直接开一个二维列表来处理每个点的可达点数,内存无疑也会爆掉,故python代码我没能写出来。

稍微算一下题目的空间:

N和M的最大数值为 30000,即数组最大初始化有 30000 个int。

开 N^2 大小的空间,就有 9*10^8 个int,我们知道 10^6 个int约等于 4M,则 9*10^8 个int会有 3600M,题目空间限制为 256M。非常遗憾,内存爆了。

稍微解释一下 “10^6 个int约等于 4M”:

4M = 1024*4kb = 1024*1024*4byte = 10^6 个int

以上,拓扑排序

祝好

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕飞雨的头发不能秃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值