贪心算法——拓扑排序

news/2024/7/3 12:25:19 标签: 贪心算法, 拓扑序列, 拓扑排序, 算法,

关于算法>贪心算法介绍:
http://blog.csdn.net/mind_v/article/details/72956707

拓扑排序">拓扑排序


问题描述

一个复杂的工程,经常可以分解成一组简单一些的任务,这些任务完成了,整个工程就完成了。例如汽车组装问题可以分解成:底盘安装、车轴安装、车轮安装、座位安装、喷漆、刹车安装、车门安装等。但是这些任务之间有个先后顺序,例如车轴安装之前先要进行底盘安装。

类似的问题,可以将任务和人物的先后顺序用有向表示——称为顶点活动网络,顶点代表一个任务,有向边(i,j)代表任务i要在任务j之前完成。下就是一个工程,它有6个任务,边(1,3)表示任务1要在任务3开始前完成,边(4,6)表示任务4要在任务6之前完成。

任务有向<a class=图" title="" />

这样就形成了一个任务序列,对有向的任意一条边(i,j),在这个序列中,任务i一定出现在任务j之前,具有这种性质的序列叫做拓扑序列(topological order),根据有向建立拓扑序列的过程称为拓扑排序(topological sorting)。

对于这样一个有向有若干个拓扑序列,如1-2-3-4-5-6,1-3-2-4-5-6,2-1-3-4-5-6等。

贪心求解

我们可以通过从左到右分步构造拓扑序列,每一步选择一个新顶点加入到序列中。选择新顶点的贪心准则:从剩余的顶点中选择一个顶点w,所有邻接于它的顶点都在序列中。

算法步骤:

令n表示有向的顶点数
令theOrder表示空虚列
while(true)
{
  令w是任意一个没有入边(v,w)的顶点,其中v不在theOrder中
  如果没有这样的顶点w,算法终止
  把w加入到theOrder的尾部
}
if(theOrder的顶点数小于n)
  算法失败
else
  theOrder是一个拓扑序列

针对上,使用这样一个算法
从theOrder是一个空序列开始,第一步选择插入theOrder序列的第一个顶点,顶点1和2都满足贪心准则。若选择1,则theOrder{1};第二步插入第二个顶点,这时有两个个候选顶点2,3。若选择3,则theOrder{1,3};第三步选择第三个顶点,候选顶点只有2,则theOrder{1,3,2};第四步候选顶点为4和5,如果选择4,则theOrder{1,3,2,4};第五步只有一个候选顶点5,第六步最后一个顶点6,则theOrder{1,3,2,4,5,6}。

数据结构选择:
用一个一维数组表示theOrder,存储拓扑序列;用一个栈存储可以加入theOrder的候选顶点; 用一个一维数组inDegree存储每个顶点的实时入度,inDegree[j]表示不在theOrder中但邻接于顶点j的数目。每次向theOrder中添加,一个顶点时,所有邻接于此顶点的顶点j,theDegree[j]减1,当inDegree变成0时,表示顶点j成为候选顶点。

C++实现

函数是的graph抽象类的成员函数,使用到的接口包括:
directed():确定是否是有向
numberOfVertices():返回的顶点数
vertexIterator类:创造一个顶点的迭代器,其next()成员返回邻接于改顶点的下一个顶点。

arrayStack是用数组描述的栈,接口:
push(i):将i压入栈
pop(),删除栈顶元素

bool topologicalOrder(int *theOrder)
{//返回false,当且仅当有向没有拓扑序列
 //如果存在一个拓扑序列,则将顶点赋给theOrder[0,n-1]

    //确定是有向
    if (!directed())
        return;

    int n = numberOfVertices();

    //计算入度
    int *inDegree = new int[n + 1];
    fill(inDegree + 1, inDegree + n + 1, 0);
    for (int i = 1; i <= n; ++i)
    {
        vertexIterator<int> *ii = iterator(i);
        int u;
        if ((u = ii->next()) != 0)
            inDegree[u]++;
    }

    //把入边数加入到栈中
    arrayStack<int> stack;
    for (int i = 1; i <= n; ++i)
        if (inDegree[i] == 0)
            stack.push(i);

    //生成拓扑序列
    int j = 0;
    while (!stack.empty())
    {
        int theVertex = stack.top();
        stack.pop();
        theOrder[j++] = theVertex;
        //更新入边数
        vertexIterator<int> *iTheVertex = iterator(theVertex);
        int u;
        while ((u = iTheVertex->next()) != 0)
        {
            inDegree[u]--;
            if (inDegree[u] == 0)
                stack.push(u);
        }
    }
    return (j == n);
}

复杂度分析:
计算入度的for循环的时间复杂度为O(n2);生成拓扑序列的外部while循环的时间复杂度为O(n),内层嵌套的while循环的时间复杂度为O(n),所以总的时间复杂度为O(n2)。故此算法的时间复杂度为O(n2)。


http://www.niftyadmin.cn/n/1050868.html

相关文章

样式不生效_可视化组队学习5:第五回:样式色彩秀芳华

内容来源: 第20期 学习者手册&#xff08;数据可视化&#xff09;​datawhale.club第五回&#xff1a;样式色彩秀芳华一、matplotlib的绘图样式&#xff08;style&#xff09;在matplotlib中&#xff0c;要想设置绘制样式&#xff0c;最简单的方法是在绘制元素时单独设置样式。…

apimodelproperty爆红_entity类中用@ApiModelProperty注解什么意思

展开全部Entity 表示当前为实体类 Id 主键 GeneratedValue(strategyGenerationType.UUID) 主键生成策略。 Column 映射字段的定义&#xff0c;包括映e68a84e8a2ad3231313335323631343130323136353331333365643662射的数据库表的字段名称。是否允许为空。字段长度等等定义。对ja…

SpringBoot入门建站全系列(十九)集成Activiti做工作流

SpringBoot入门建站全系列&#xff08;十九&#xff09;集成Activiti做工作流 一、概述 Activiti作为一个流行的开源工作流引擎&#xff0c;正在不断发展&#xff0c;其6.0版本以API形式提供服务&#xff0c;而之前版本基本都是要求我们的应用以JDK方式与其交互&#xff0c;只…

使用computed_详解Vue中的computed和watch

1. 前言 作为一名Vue开发者&#xff0c;虽然在项目中频繁使用过computed和watch&#xff0c;但从来没有系统的学习过&#xff0c;总觉着对这两个知识点有些一知半解。如果你也和我一样&#xff0c;就一起来回顾和总结一下这两个知识点吧。本篇非源码分析&#xff0c;只是从两者…

全景图拍摄_全景图拍摄步骤简介

1选好位置&#xff0c;将三角架、节点云台、照相机调整好备用位置选择&#xff0c;请注意视野&#xff0c;避免相机顶部有遮挡物&#xff0c;减少阴影面积&#xff1b;节点云台固定较为重要&#xff0c;确定了支点位置之后&#xff0c;以此为轴后不可移动&#xff0c;进行拍摄。…

thinkphp mysql缓存_thinkPHP5框架数据库连贯操作之cache()用法分析

本文实例讲述了thinkPHP5框架数据库连贯操作之cache()用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;介绍TP5中自带的缓存系统&#xff0c;是File型缓存。也就是文件型缓存。存储地址是&#xff1a;根目录\..\runtime\cache(根目录指public)。这个缓存系统相较于…

Web基础配置篇(十): ActiveMQ与RabbitMQ的安装配置及使用

Web基础配置篇&#xff08;十&#xff09;: ActiveMQ与RabbitMQ的安装配置及使用 一、概述 消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流&#xff0c;并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型&#xff0c;它可以在分布式环境下…

SpringCloud技术指南系列(一)服务注册发现之Eureka注册中心

SpringCloud技术指南系列&#xff08;一&#xff09;服务注册发现之Eureka注册中心 SpringCloud所谓的服务注册与发现&#xff0c;流程大致是&#xff1a; 将Springboot微服务客户端项目的地址等信息&#xff0c;通过网络发送到注册中心&#xff0c;由注册中心保存下来。 另一…