当前位置: 首页 > backend >正文

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

拓扑排序算法

前置知识:

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

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

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

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

kahn(卡恩)算法

可以判环

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

有环就没有拓扑序列

#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 杂务 - 洛谷

#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 普及组] 车站分级 - 洛谷

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int n,m; 
vector<int> g[1005];
int s[1005];
int flag[1005];
int pd[1005][1005];//判断i--> j 的边是否已经建立
int ind[1005]; 
int le[1005];//级别 void kahn(){queue<int> 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<g[x].size();i++){y=g[x][i];le[y]=max(le[y],le[x]+1);ind[y]--;if(ind[y]==0){q.push(y);}}}
}int main(){cin>>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<<ans;return 0;
} 

基于DFS的算法

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

直接求

#include<bits/stdc++.h>
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<int> 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<<topo.top()<<" ";topo.pop();} return 0;
} 

可以判环

#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;
stack<int> 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<<"有环"<<endl;return 0; } while(!topo.empty()){cout<<topo.top()<<" ";topo.pop();} return 0;
} 
http://www.xdnf.cn/news/16083.html

相关文章:

  • 关于网络安全等级保护的那些事
  • 重磅发布:Oracle ADG 一键自动化搭建脚本
  • java设计模式 -【策略模式】
  • 为什么本地ip记录成0.0.0.1
  • 扫地机产品--同理心地图的方法,展现一个功能的痛点提炼
  • 智能营销革命:AI如何重塑个性化广告的创作逻辑
  • 汽车电子架构
  • LeetCode热题100--24. 两两交换链表中的节点--中等
  • 视频孪生赋能数字住建:构建智慧城市新蓝图​
  • TDengine 的 HISTOGRAM() 函数用户手册
  • 如何在 npm 上发布 Element Plus 二次封装组件
  • 算法竞赛备赛——【图论】最小生成树
  • 关于针对 DT_REG 出现红色波浪线的问题(编译错误/IDE警告),以下是 精准解决方案,保持你的代码功能完全不变:
  • 基于数据挖掘的短视频点赞影响因素分析【LightGBM、XGBoost、随机森林、smote】
  • 如何在macOS上修改iPhone的定位
  • uniapp拦截返回事件
  • Android Multidex 完全解析:解决64K方法数限制
  • LLM 幻觉一般是由于什么产生的,在模型什么部位产生
  • 编程与数学 03-001 计算机组成原理 21_服务器计算机组成实例解析
  • Django学习之旅--第13课:Django模型关系进阶与查询优化实战
  • STM32 基础知识 定时器【概念】
  • Go语言实现DNS解析与域名服务:从基础到生产实践
  • SOLIDWORKS2025教育版集成了电气与自动化设计功能
  • 内存飙升但无 OOM?用 eBPF 捕获隐性内存泄漏事件
  • 7.23总结设备虚拟化技术
  • 统一服务入口——Spring Cloud Gateway
  • Unreal5从入门到精通之使用 Python 编写虚幻编辑器脚本
  • 旧手机部署轻量级服务器
  • 什么是MySQL 视图
  • MySQL binlog解析