首页 > 其他分享 >DAG拓扑排序

DAG拓扑排序

时间:2023-11-29 13:22:05浏览次数:33  
标签:DAG int 拓扑 序列 顶点 排序

DAG拓扑排序

引入

小学奥数类型题。

沏茶过程

(烧水壶) 到 (接水) 到 (烧水 洗茶杯 找茶叶)(并行) 到 (沏茶)

即有先后顺序的流程,且必须所有步骤都能执行。

概述

  • 拓扑排序是对DAG(有向无环图)的顶点进行的一种线性排序,排序序列中每个顶点都会且仅会出现一次,且对于所有有向边 \(u\rightarrow v\),排序完后 \(u\) 都在 \(v\) 的后面。
  • 如果图中存在环,就不能进行拓扑排序。
  • 一个有向无环图可能有多种排序结果。
    • 对于 \(n\) 个顶点的有向无环图:
      • 最少存在 \(1\) 种合法的拓扑序列。
        • 即该图为一条直线。
      • 最多存在 \(n!\) 钟合法的拓扑序列。
        • 即该图为散点,无边。

流程

  • 在拓扑排序中,用 \(L\) 记录到目前为止的拓扑序列,用集合 \(S\) 记录所有不在 \(L\) 中入度为 \(0\) 的顶点。
  • 步骤执行
    • 首先遍历整张图上的顶点,如果一个顶点入度为 \(0\),将它加入 \(S\)。
    • 当 \(S\) 不为空时:
      • 在 \(S\) 中任取一个顶点 \(x\),将 \(x\) 加入到 \(L\) 的队尾,并把 \(x\) 从 \(S\) 中删去。
      • 遍历从 \(x\) 出发的边 \(x\rightarrow y\),删除。如果 \(y\) 的入度变为 \(0\),则将其加入 \(S\) 中。
    • 循环结束时:
      • 如果所有点都加入了 \(L\),那么我们就找到了一个合法的拓扑序列。
      • 如果有点不在 \(L\) 中,证明该图有环。
  • \(L,S\) 用同一个队列维护。
  • 时间复杂度 \(\operatorname O(n + m)\)

代码

vector<int> edge[N + 1];
int n, m, q[N + 1], d[N + 1]//q为队列,d为入度;

void topoSort()
{
	int front = 1, rear = 0;
    for (int i = 1; i <= n; i++)
    {
		if (!d[i]) q[++rear] = i;
        while(front <= rear)
        {
            int x = q[front];
            ++front;
            for (auto to : edge[x])
            {
                if (--d[to] == 0)//没必要真的删边,维护d数组即可
                {
					q[++rear] = to;
                }
            }
        }
    }
    if (rear == n)
    {
		printf("合法");
    }
    else
    {
		printf("不合法");
    }
}

标签:DAG,int,拓扑,序列,顶点,排序
From: https://www.cnblogs.com/kdlyh/p/17864601.html

相关文章

  • 快速排序带选取中位数的写法
    1.以i为基准,且不带选取中位数的写法//从小到大voidquick_sort(intq[],intl,intr){if(l>=r)return;inti=l-1,j=r+1,x=q[l+r+1>>1];//注意是向上取整,因为向下取整可能使得x取到q[l]while(i<j){doi++;while(q[i......
  • 冒泡排序!!!!!
    packagearray;importjava.util.Arrays;publicclassArrayDemo07{publicstaticvoidmain(String[]args){int[]a={1,4,5,6,72,2,2,2,25,6,7};int[]sort=sort(a);//调用完我们自己写的排序方法以后,返回一个排序后的数组System.......
  • 冒泡排序:要比较(二层循环)n*(n-1)(第一层循环)次,最大的在最后,最次大的在倒数第二,
    privatestatic voidsort(int[]w,intl,intr){//冒泡排序要比较n二层循环*(n-1)次,第一层循环      for(inti=r;i>l;i--){        for(intj=l;j<i;j++){          if(w[j]>w[j+1])          { ......
  • 排序算法之冒泡排序优化2
    一:概述对于冒泡排序的优化1中,右边的许多元素已经是有序的了,可是每一轮还是白白地比较多次了。这个问题地关键点在于对数列有序区地界定。按照现有的逻辑,有序区的长度和排序的轮数是相等的。例如第1轮排序过后的有序区长度是1,第2轮排序过后的有序长度是2....实际上,数列真正的有序区......
  • C# Lambda 分组排序问题(先对数据进行时间倒序排列,然后再按照某字符分组,在每个分组内再
    问题:先对数据进行时间倒序排列,然后再按照某字符分组,在每个分组内再按照某数字或字符正序排列解答:vardata=list.OrderByDescending(i=>i.Date).ToList();vargData=data.GroupBy(g=>g.code).Select(l=>l.OrderBy(i=>i.Step));varinvData=newList<IndexVM>();fore......
  • O(nlogn)排序算法
    排序算法介绍常见时间复杂度为\(O(nlogn)\)的排序算法1.快速排序分治思想#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+10;inta[N];voidquick_sort(intl,intr){if(l>=r)return;intx=a[l+r>>1],i=l-1,j=r+1;......
  • 数字在排序数组中出现的次数--二分
    题目描述有序序列二分先对左端点进行二分再对右端点二分最后得到两个端点,直接相减+1,得到区间个数classSolution{public:intgetNumberOfK(vector<int>&nums,intk){if(nums.empty())return0;intl=0,r=nums.size()-1;while(l<r......
  • 数组作为函数参数(冒泡排序)
    往往我们在导代码的时候,会将数组作为参数传个函数,比如我们要实现一个冒泡排序:函数讲一个整形数组进行排序(主要讲算法思想)#include<stdio.h>voidbubble_sort(intarr[],intsz){inti=0;//确认冒泡函数的趟数//intsz=sizeof(arr)/sizeof(arr[0]);//注:这里不能在void函......
  • Django - 多条queryset合并,并排序
     fromitertoolsimportchainfromoperatorimportattrgetter#拿到多条querysetqueryset1=model.objects.filter(status=1).all()queryset2=model.objects.filter(status=2).all()#将上面两组查询结果合并,并设置排序方式:-create_timenew_queryset=sorted......
  • 排序算法之冒泡排序优化1
    一:概述原始的数列{4,8,6,3,9,2,1,7},执行至第6步和第7步时,数列状态如下:很明显的可以看出,经过第6轮排序之后,整个数列已然是有序的了。可是排序算法依然是继续执行第7轮排序。在这种情况下,如果能判断出数列已经有序,并作出标记,那么剩下的几轮就不必执行了,可以提前结束。二:具体代码优化的......