拓扑排序:利用kahn算法。c++

拓扑排序

拓扑排序要解决的问题是给一个图的所有节点排序。在一个有向无环图DAG中,我们将图中的顶点以线性的方式进行排序,对于有向边(u,v),确保u在v的前面,认为v依赖于u; 如果u到v有路径,u可达v,称v间接依赖于u

拓扑排序可以用于解决先导课,途经车站等可以转化为有向图的题目。如果有向图中出现了环,就没有办法进行拓扑排序了

Kahn算法

  • 对于一个图,首先将所有入度为0的点组成一个集合S(S通常使用队列表示)
  • 每次从S中取出一个点 u 放入 L ,遍历以 u 为出发点的边 (u,v)并进行删除,如果在删除了该边后,顶点 v 的入度变为 0 ,就将顶点 v 放入集合S中。
  • 不断重复上述过程知道集合为空
  • 如果最后集合为空的时候图中还存在边,则图一定存在环路,它无法进行拓扑排序;如果没有边,输出L,L中的顺序就是拓扑排序的结果

比如对于下面这个图:
第一步就是寻找入度为0的点将他放到队列中,将2,8 放入;
然后取出2 开始寻找2能到达的点,先删除边(2,0),在删除了这条边后0的入度变为0,所以将0加入队列;
继续删除边(2,3),删除后3的入度变为0,将3加入队列;
然后再从队列中取出8开始重复过程…在这里插入图片描述例题:名次排序

一共有 N 只猫猫,编号依次为1,2,3,…,N进行比赛。现在我们知道每场比赛的结果,请你编程序确定字典序最小的名次序列

输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示猫猫的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即编号为 P1 的猫猫赢了编号为 P2 的猫猫

给出一个符合要求的排名。输出时猫猫的编号之间有空格,最后一名后面没有空格!
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名

sample input:
4 3
1 2
2 3
4 3

sample output:
1 2 4 3

思路:

  • 因为给出了所有的胜负关系,所以可以构建一张有向无环图
  • t1 胜 t2 等价于图中存在一条 (t1,t2) 边
  • 因为要求最终输出字典序最小的拓扑排序,所以使用优先级队列
  • 拓扑排序的思路就是Kahn算法的思路
  • 刚开始答案一直不对是因为在初始化入度的时候从0开始了,但实际上这道题并不存在0号顶点,就会导致输出答案的错误
#include<iostream>
#include<cstdio>
#include<string.h>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
const int TOP=5e3+2;
int N,M;
struct edge
{
 int to,next;
}e[TOP];
int head[TOP],in_deg[TOP],tot;
priority_queue<int,vector<int>,greater<int> >q;
vector<int> ans;
void add(int t1,int t2)
{
 e[tot].to=t2;
 e[tot].next=head[t1];
 head[t1]=tot;
 in_deg[t2]++;
 tot++;
}
void toposort()
{
 for(int i=1;i<=N;i++)//这里有个坑orz 
 {
  if(in_deg[i]==0) 
  q.push(i);
 }
 bool visit[TOP];
 memset(visit,true,sizeof(visit));
 while(!q.empty())
 {
  int u=q.top();
  q.pop();
  ans.push_back(u);
  for(int i=head[u];i!=-1;i=e[i].next)
  {
   int temp=e[i].to;
   if(visit[i])
   {
    in_deg[temp]--;
    if(in_deg[temp]==0)
     q.push(temp);
     visit[i]=false;
   }
  }
 }
 cout<<ans[0];
 for(int i=1;i<N;i++)
 cout<<" "<<ans[i];
 cout<<endl;
} 
int main()
{
 while(scanf("%d%d",&N,&M)!=EOF)
 {
  tot=0;
  memset(head,-1,sizeof(head));
  memset(in_deg,0,sizeof(in_deg));
  ans.clear();
  while(M--)
  {
   int t1,t2;
   scanf("%d%d",&t1,&t2);
   add(t1,t2);
  }
  toposort();
 }
 return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值