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

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

拓扑排序算法

前置知识:

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.dtcms.com/a/293695.html

相关文章:

  • PAT 甲级题目讲解:1002《A+B for Polynomials》
  • 二分查找----2.搜索二维矩阵
  • (13)机器学习小白入门YOLOv:YOLOv8-cls中用TensorBoard实时监控指标
  • 深入浅出理解 Reactor:响应式编程的利器​
  • Github上传文件流程图
  • Docker 应用数据备份、迁移方案
  • Redis原理之分布式锁
  • 武德物业和浑元科技-《软件方法》第2章业务建模之愿景03
  • Oracle物化视图详解
  • 计算机网络第四章(4)——网络层《无分类编址CIDR、路由聚合》
  • ESP32-CAM实战:DIY基于OpenAI的AI视觉识别相机
  • 校园后勤服务平台小程序的设计与实现
  • Android埋点实现方案深度分析
  • 新手向:Idea的使用技巧
  • Android 架构演进:从 MVC 到 MVVM 的设计之道
  • SpringCloud seata全局事务
  • python在windows电脑找回WiFi密码
  • LinkedList的模拟实现+LinkedList和ArrayList的区别
  • 使用 Maven 的 `maven-assembly-plugin` 插件打包zip
  • UE5实现NPC头部朝向玩家功能
  • 旧手机部署轻量级服务器
  • HakcMyVM-Luz
  • 解构未来金融:深入剖析DeFi与去中心化交易所(DEX)的技术架构
  • ZooKeeper在Hadoop中的协同应用:从NameNode选主到分布式锁实现
  • CSS 基础
  • Web 服务器和Web 中间件
  • Apache POI 介绍与使用指南
  • 思路探索:当大型语言模型遇见数据分析的现实挑战
  • 利用中间件实现任务去重与分发精细化:股吧舆情数据采集与分析实战
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 主页-最近七天微博发布量实现