拓扑排序详解
拓扑排序#
定义#
拓扑排序是一种在有向无环图(也称
算法实现#
-
找到图中没有前驱的节点(或者说是入度为
的节点)输入; -
然后从图中将此节点删除并且删除以该节点为起点的边;
为什么要这么做呢?
上面已经提到,对于一条边(应该讲明白了吧)。
代码及题目练习#
这道题的题意已经很清楚了,就是问你到点
代码如下:
#include<bits/stdc++.h>
#define N 1000010
using namespace std;
int n,m,cnt,head[N],dep[N],du[N];//dep存放每一个点的最大深度,du存放每一个点的入度
struct edge{int v,next;}e[N<<1];//链式前向星存边
inline void add(int u,int v)//加边函数
{
e[++cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt;
}
void topsort()//拓扑排序主体
{
queue<int>q;//队列辅助进行拓扑排序
for(int i=1;i<=n;i++)//一开始先遍历每一个点
if(!du[i])//如果入度为零
q.push(i),dep[i]=1;//直接入列,标记深度为1
while(!q.empty())//只要队列不空就还有点没有排好序
{
int u=q.front();//取出队头元素
q.pop();//弹出
for(int i=head[u];i;i=e[i].next)//遍历每一条与u相连的边
{
int v=e[i].v;//取出终点
dep[v]=dep[u]+1;//更新终点的最大深度
du[v]--;//终点入度减一,相当于把此边删除
if(!du[v])//如果当前终点的入度为0了
q.push(v);//入列
}
}
return ;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v);//存有向图
du[v]++;//终点入度加一
}
topsort();//进行拓扑排序
for(int i=1;i<=n;i++)
cout<<dep[i]<<endl;//输出答案
return 0;//好习惯
}
这道题刚拿到手没搞明白公式是什么意思,但仔细读了一下发现
代码如下:
#include<bits/stdc++.h>
#define int long long
#define N 1010
using namespace std;
int n,m,ci[N],ui[N],head[N<<4],cnt,du[N],ou[N];//ciui如题所示,du记录入度,ou记录出度
struct edge{int v,w,next;}e[N<<4];//结构体存边
queue<int>q;
inline void add(int u,int v,int w)//加边函数
{
e[++cnt].w=w;
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt;
}
void topsort()//拓扑排序主体
{
while(!q.empty())//只要队列不空就没排完
{
int u=q.front();q.pop();//取出队头元素并弹出
for(int i=head[u];i;i=e[i].next)//遍历每一条与之相连的边
{
int v=e[i].v;//取出终点
du[v]--;//终点入度减一
if(ci[u]>0)//如果当前起点的ci大于0才能往终点传输
ci[v]+=e[i].w*ci[u];//计算累加求和
if(!du[v])//如果终点的入度为0了
{
q.push(v);//把终点放入队列
ci[v]-=ui[v];//减去ui
}
}
}
return ;
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>ci[i]>>ui[i];//输入当前点的信息
if(ci[i]>0)q.push(i);//只有ci大于0的才能向其他点传输
}
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);//建有向图
du[v]++;//入度,拓扑用
ou[u]++;//出度,判断是不是输出层
}
topsort();//拓扑排序
int flag=0;//flag标记是否有输出层不为0的点
for(int i=1;i<=n;i++)//遍历每一个点
if(ci[i]>0&&!ou[i])//如果是输出层且ci大于0
flag=1,//标记flag
cout<<i<<" "<<ci[i]<<endl;//输出
if(!flag)//如果flag是0
cout<<"NULL"<<endl;//输出NULL
return 0;//好习惯
}
虽然拓扑排序看上去很简单,但正是因为他太简单了所以很灵活,有很多题一般是看不出来要用拓扑排序来做的,当你遇到某一个题目的时候可以找一下隐藏条件,如果他是一个有向无环图的话就可以优先考虑一下拓扑排序。
作者: 北烛青澜
出处:https://www.cnblogs.com/Multitree/p/16673850.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!