算法竞赛备赛——【图论】拓扑排序

拓扑排序算法

前置知识:

1.DAG图:一个无环的有向图,即有向无环图。

2.AOV网络:在⼀个表示⼯程的有向图中,⽤顶点表示活动,⽤弧表示活动之间的优先关系的有向图称为顶点表示活动的⽹(Activity On Vertex Network),简称AOV⽹。

拓扑排序:其实就是对⼀个DAG图构造拓扑序列的过程。

拓扑排序算法:kahn(卡恩)算法(基于BFS)和 基于DFS的算法。

kahn(卡恩)算法

可以判环

时间复杂度:O(V+E)

有环就没有拓扑序列

C++ 复制代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;

//有向图------>判环 
int n,m;
struct Edge{//只求拓扑序列不用带边权 
	int to,next;
}e[10005];
int h[105];
int ind[105];//入度 
int cnt;
int topo[105],k=0;

void add(int u,int v){
	e[cnt].to=v;
	e[cnt].next=h[u];
	h[u]=cnt;
	cnt++; 
} 

bool kahn(){
	queue<int> q;
	for(int i=1;i<=n;++i){
		if(ind[i]==0){
			q.push(i);
		}
	}
	int x,y;
	while(!q.empty()){
		x=q.front();
		q.pop();
		topo[++k]=x;//从1开始计数 
		for(int i=h[x];i!=-1;i=e[i].next) {
			y=e[i].to;
			ind[y]--;
			if(ind[y]==0) q.push(y); 
		}
	}
	if(k==n) return true;//无环 
	else return false;//成环 
} 

int main(){
	cin>>n>>m;
	memset(h,-1,sizeof h);
	int u,v;
	for(int i=1;i<=m;++i){
		cin>>u>>v;
		add(u,v);
		ind[v]++;
	}
	if(kahn()){
		for(int i=1;i<=k;++i){
			cout<<topo[i]<<" ";
		}
	} else{
		cout<<"有环\n"; 
	}
	return 0;
} 

例题

P1113 杂务 - 洛谷

C++ 复制代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int n; 
struct Edge{
	int to,next;
}e[100005];
int h[10005],cnt;
int ind[10005];
int t[10005];//每个点需要的时间 
int ed[10005];//每个点的完成时间 

void add(int u,int v){
	e[cnt].to=v;
	e[cnt].next=h[u];
	h[u]=cnt;
	cnt++;
}

void kahn(){
	queue<int> q;
	for(int i=1;i<=n;++i){
		if(ind[i]==0){
			q.push(i);
			ed[i]=t[i];//没有前置活动 
		}
	}
	int u,v;
	while(!q.empty()){
		u=q.front();
		q.pop();
		for(int i=h[u];~i;i=e[i].next){
			v=e[i].to;
			ind[v]--;
			ed[v]=max(ed[v],ed[u]+t[v]); //更新y的结束时间 
			if(ind[v]==0){
				q.push(v);
			}
		} 
	}
}

int main(){
	cin>>n;
	int u,v;
	memset(h,-1,sizeof h);
	for(int i=1;i<=n;++i){
		cin>>u;
		cin>>t[u];//注意不要同行读入
		while(cin>>v){
			if(v==0) break;
			add(u,v);
			ind[v]++;
		}
	}
	kahn();
	int ans=-1;
	for(int i=1;i<=n;++i){
		ans=max(ans,ed[i]);
	} 
	cout<<ans<<endl;
	return 0;
} 

P1983 [NOIP 2013 普及组\] 车站分级 - 洛谷](https://www.luogu.com.cn/problem/P1983) ```C++ #include using namespace std; using ll=long long; int n,m; vector g[1005]; int s[1005]; int flag[1005]; int pd[1005][1005];//判断i--> j 的边是否已经建立 int ind[1005]; int le[1005];//级别 void kahn(){ queue q; for(int i=1;i<=n;++i){ if(ind[i]==0){ q.push(i); le[i]=1; } } int x,y; while(!q.empty()){ x=q.front(); q.pop(); for(int i=0;i>n>>m; int sn; for(int i=1;i<=m;++i){ cin>>sn;//第i趟线路停靠sn个站 memset(flag,0,sizeof(flag)); for(int j=1;j<=sn;++j){ cin>>s[j]; flag[s[j]]=1;//s[j]站停靠了 } for(int j=s[1];j<=s[sn];j++){//枚举该线路中所有没停靠的站 if(flag[j]==1) continue; for(int k=1;k<=sn;k++){ if(pd[j][s[k]]==0){//避免重复建边 g[j].push_back(s[k]); pd[j][s[k]]=1; ind[s[k]]++; } } } } kahn(); int ans=-1; for(int i=1;i<=n;++i){ ans=max(ans,le[i]); } cout< using namespace std; using ll=long long; //有向图------>保证是DAG图 无环 int n,m; struct Edge{//只求拓扑序列不用带边权 int to,next; }e[10005]; int h[105]; int ind[105];//入度 int cnt; stack topo; int vis[105]; void add(int u,int v){ e[cnt].to=v; e[cnt].next=h[u]; h[u]=cnt; cnt++; } void DFS(int x){ vis[x]=1; int y; for(int i=h[x];~i;i=e[i].next){ y=e[i].to; if(vis[y]==0){ DFS(y); } } topo.push(x);//返回时入栈 } int main(){ cin>>n>>m; memset(h,-1,sizeof h); int u,v; for(int i=1;i<=m;++i){ cin>>u>>v; add(u,v); ind[v]++; } for(int i=1;i<=n;++i){ if(vis[i]==0){ DFS(i); } } while(!topo.empty()){ cout< using namespace std; using ll=long long; //有向图------>判环 int n,m; struct Edge{//只求拓扑序列不用带边权 int to,next; }e[10005]; int h[105]; int ind[105];//入度 int cnt; stack topo; int vis[105]; //vis[i]=0 还未走过/还未遍历过 // =1 该点及其后面所有的点已经访问完了---->回溯时标记为1 // =2 这个点走过一次了 现在正在遍历该点后面的点---->第一次访问标记为2 int flag=0;//标记是否有环 void add(int u,int v){ e[cnt].to=v; e[cnt].next=h[u]; h[u]=cnt; cnt++; } void DFS(int x){ vis[x]=2; int y; for(int i=h[x];~i;i=e[i].next){ y=e[i].to; if(vis[y]==2){ flag=1; //ans=y; //可以用ans来记录环从哪里开始 return ; } else if(vis[y]==0){ DFS(y); if(flag==1){ return ; } } } topo.push(x);//返回时入栈 vis[x]=1; //x及其后面的点访问结束 } int main(){ cin>>n>>m; memset(h,-1,sizeof h); int u,v; for(int i=1;i<=m;++i){ cin>>u>>v; add(u,v); ind[v]++; } for(int i=1;i<=n;++i){ if(vis[i]==0){ DFS(i); } } if(flag==1){ cout<<"有环"<

相关推荐
UP_Continue9 分钟前
算法讲解--有效三角形的个数
数据结构
小比卡丘17 分钟前
【C++进阶】第7课—红黑树
java·开发语言·c++
Morriser莫42 分钟前
动态规划Day1学习心得
算法·动态规划
lifallen1 小时前
Flink堆状态后端核心:CopyOnWriteStateMap解析
java·大数据·数据结构·数据库·算法·flink·哈希算法
序属秋秋秋3 小时前
《C++初阶之STL》【vector容器:详解 + 实现】
开发语言·c++·笔记·学习·stl
科大饭桶6 小时前
数据结构自学Day13 -- 快速排序--“分而治之”
数据结构·算法·排序算法
lixzest7 小时前
快速梳理遗留项目
java·c++·python
某个默默无闻奋斗的人7 小时前
【矩阵专题】Leetcode54.螺旋矩阵(Hot100)
java·算法·leetcode
郝学胜-神的一滴8 小时前
建造者模式:构建复杂对象的优雅方式
开发语言·c++·程序人生·建造者模式
JXL18608 小时前
Leetcode-.42接雨水
算法·leetcode·职场和发展