算法 图8 How Long Does It Take
全部每周作业和视频思考题答案和解析 见 浙江大学 数据结构 思考题+每周练习答案
题目:Given the relations of all the activities of a project, you are supposed to find the earliest completion time of the project.
Input Specification:
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of activity check points (hence it is assumed that the check points are numbered from 0 to N−1), and M, the number of activities. Then M lines follow, each gives the description of an activity. For the i
-th activity, three non-negative numbers are given: S[i]
, E[i]
, and L[i]
, where S[i]
is the index of the starting check point, E[i]
of the ending check point, and L[i]
the lasting time of the activity. The numbers in a line are separated by a space.
每个输入文件包含一个测试用例。每种情况都以一行开始,该行包含两个正整数N(≤100)、活动检查点的数量(因此,假设检查点的编号范围为0到N-1)和M,即活动数量。接下来是M行,每行给出一个活动的描述。对于第i个活动,给出了三个非负数:S[i],E[i]和L[i],其中S[i]是开始检查点的索引,E[i]是结束检查点,L[i]是活动的持续时间。一行中的数字用空格隔开。
Output Specification:
For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output "Impossible".
Sample Input 1:
9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
Sample Output 1:
18
Sample Input 2:
4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5
Sample Output 2:
Impossible
解答:
思路很简单,构成一个拓扑排序,把每层最多需要的时间记录,逐层记录。
这里需要注意,我们的拓扑结构是最简单的任务,不需要保证某些步骤同步进行,视频里说了一种复杂的情况,与该题无关,我之前就混淆了。
我们先整理一个使用邻接表存储的拓扑排序程序:
注意因为是有向图,所以插入边的操作需要去掉后半部分。题目给的顶点序号是0到N-1,所以不需要读入数据再减一(参考上个题,顶点序号1-N,所以需要进一步处理)。
#include <iostream>
#include <queue>
using namespace std;#define MaxVertexNum 1000
typedef int Vertex;// 邻接表存储 - Kruskal最小生成树算法 //-------------------- 顶点并查集定义 --------------------
typedef Vertex ElementType; // 默认元素可以用非负整数表示
typedef Vertex SetName; // 默认用根结点的下标作为集合名称
typedef ElementType SetType[MaxVertexNum]; // 假设集合元素下标从0开始
typedef int WeightType; // 边的权值设为整型
typedef char DataType; // 顶点存储的数据类型设为字符型 queue<Vertex> myQueue;// 边的定义
typedef struct ENode *PtrToENode;
struct ENode {Vertex V1, V2; // 有向边<V1, V2> WeightType Weight; // 权重
};
typedef PtrToENode Edge;
//邻接点的定义
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode {Vertex AdjV; // 邻接点下标 WeightType Weight; // 边权重 PtrToAdjVNode Next; // 指向下一个邻接点的指针
};
//顶点表头结点的定义
typedef struct Vnode {PtrToAdjVNode FirstEdge; // 边表头指针 DataType Data; // 存顶点的数据 // 注意:很多情况下,顶点无数据,此时Data可以不用出现
} AdjList[MaxVertexNum]; // AdjList是邻接表类型
//图结点的定义
typedef struct GNode *PtrToGNode;
struct GNode {int Nv; // 顶点数 int Ne; // 边数 AdjList G; // 邻接表
};
typedef PtrToGNode LGraph; // 以邻接表方式存储的图类型 LGraph CreateGraph(int VertexNum)
{ //初始化一个有VertexNum个顶点但没有边的图 Vertex V;LGraph Graph;Graph = (LGraph)malloc(sizeof(struct GNode)); // 建立图 Graph->Nv = VertexNum;Graph->Ne = 0;//初始化邻接表头指针 //注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) for (V = 0; V<Graph->Nv; V++)Graph->G[V].FirstEdge = NULL;return Graph;
}void InsertEdge(LGraph Graph, Edge E)
{PtrToAdjVNode NewNode;//插入边 <V1, V2> //为V2建立新的邻接点 NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));NewNode->AdjV = E->V2;NewNode->Weight = E->Weight;//将V2插入V1的表头 NewNode->Next = Graph->G[E->V1].FirstEdge;Graph->G[E->V1].FirstEdge = NewNode;//注意拓扑排序是用的有向图//若是无向图,还要插入边 <V2, V1> //为V1建立新的邻接点 //NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));//NewNode->AdjV = E->V1;//NewNode->Weight = E->Weight;//将V1插入V2的表头 //NewNode->Next = Graph->G[E->V2].FirstEdge;//Graph->G[E->V2].FirstEdge = NewNode;
}LGraph BuildGraph()
{LGraph Graph;Edge E;Vertex V;int Nv, i;cin >> Nv; //读入顶点个数 Graph = CreateGraph(Nv); //初始化有Nv个顶点但没有边的图 cin >> Graph->Ne; //读入边数 if (Graph->Ne != 0) { //如果有边 E = (Edge)malloc(sizeof(struct ENode)); //建立边结点 //读入边,格式为"起点 终点 权重",插入邻接矩阵 for (i = 0; i<Graph->Ne; i++) {cin >> E->V1 >> E->V2 >> E->Weight;//E->V1--;//E->V2--;//注意:如果权重不是整型,Weight的读入格式要改 InsertEdge(Graph, E);}}//如果顶点有数据的话,读入数据 //for (V = 0; V<Graph->Nv; V++)//cin >> Graph->G[V].Data;return Graph;
}//邻接表存储 - 拓扑排序算法
bool TopSort(LGraph Graph, Vertex TopOrder[])
{ //对Graph进行拓扑排序, TopOrder[]顺序存储排序后的顶点下标 int Indegree[MaxVertexNum], cnt;Vertex V;PtrToAdjVNode W;//初始化Indegree[] for (V = 0; V<Graph->Nv; V++)Indegree[V] = 0;//遍历图,得到Indegree[] for (V = 0; V<Graph->Nv; V++)for (W = Graph->G[V].FirstEdge; W; W = W->Next)Indegree[W->AdjV]++; //对有向边<V, W->AdjV>累计终点的入度 //将所有入度为0的顶点入列 for (V = 0; V < Graph->Nv; V++)if (Indegree[V] == 0)myQueue.push(V);//下面进入拓扑排序 cnt = 0;while (!myQueue.empty()) {V = myQueue.front(); //弹出一个入度为0的顶点 myQueue.pop();TopOrder[cnt++] = V; //将之存为结果序列的下一个元素 //对V的每个邻接点W->AdjV for (W = Graph->G[V].FirstEdge; W; W = W->Next)if (--Indegree[W->AdjV] == 0)//若删除V使得W->AdjV入度为0 myQueue.push(W->AdjV); //则该顶点入列 } //while结束if (cnt != Graph->Nv)return false; //说明图中有回路, 返回不成功标志 elsereturn true;
}
int main(void) {LGraph myGraph = BuildGraph();Vertex TopOrder[MaxVertexNum];bool flag = TopSort(myGraph, TopOrder);if (true == flag) {for (int i = 0;i < myGraph->Nv;i++) {cout << TopOrder[i] << " ";}cout << endl;}else {cout << " 有回路 " << endl;}cout << endl;system("pause");return 0;
}
打印输出结果为:0 3 2 1 5 4 7 6 8
说明我们的拓扑排序程序是正确的。
然后我们只需要在每个点到其连接点的判断中加入一句话:
if ((Earliest[V] + W->Weight)>Earliest[W->AdjV]) {Earliest[W->AdjV] = Earliest[V] + W->Weight;}
也就是说找到每一组到后面最大的数。
然后最后别忘了要找到Earliest数组里面最大的数,因为最大的数才是总项目最短完成时间。
全部代码如下:
#include <iostream>
#include <queue>
using namespace std;#define MaxVertexNum 1000
typedef int Vertex;// 邻接表存储 - Kruskal最小生成树算法 //-------------------- 顶点并查集定义 --------------------
typedef Vertex ElementType; // 默认元素可以用非负整数表示
typedef Vertex SetName; // 默认用根结点的下标作为集合名称
typedef ElementType SetType[MaxVertexNum]; // 假设集合元素下标从0开始
typedef int WeightType; // 边的权值设为整型
typedef char DataType; // 顶点存储的数据类型设为字符型
Vertex Earliest[MaxVertexNum];
queue<Vertex> myQueue;// 边的定义
typedef struct ENode *PtrToENode;
struct ENode {Vertex V1, V2; // 有向边<V1, V2> WeightType Weight; // 权重
};
typedef PtrToENode Edge;
//邻接点的定义
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode {Vertex AdjV; // 邻接点下标 WeightType Weight; // 边权重 PtrToAdjVNode Next; // 指向下一个邻接点的指针
};
//顶点表头结点的定义
typedef struct Vnode {PtrToAdjVNode FirstEdge; // 边表头指针 DataType Data; // 存顶点的数据 // 注意:很多情况下,顶点无数据,此时Data可以不用出现
} AdjList[MaxVertexNum]; // AdjList是邻接表类型
//图结点的定义
typedef struct GNode *PtrToGNode;
struct GNode {int Nv; // 顶点数 int Ne; // 边数 AdjList G; // 邻接表
};
typedef PtrToGNode LGraph; // 以邻接表方式存储的图类型 LGraph CreateGraph(int VertexNum)
{ //初始化一个有VertexNum个顶点但没有边的图 Vertex V;LGraph Graph;Graph = (LGraph)malloc(sizeof(struct GNode)); // 建立图 Graph->Nv = VertexNum;Graph->Ne = 0;//初始化邻接表头指针 //注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) for (V = 0; V<Graph->Nv; V++)Graph->G[V].FirstEdge = NULL;return Graph;
}void InsertEdge(LGraph Graph, Edge E)
{PtrToAdjVNode NewNode;//插入边 <V1, V2> //为V2建立新的邻接点 NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));NewNode->AdjV = E->V2;NewNode->Weight = E->Weight;//将V2插入V1的表头 NewNode->Next = Graph->G[E->V1].FirstEdge;Graph->G[E->V1].FirstEdge = NewNode;//注意拓扑排序是用的有向图//若是无向图,还要插入边 <V2, V1> //为V1建立新的邻接点 //NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));//NewNode->AdjV = E->V1;//NewNode->Weight = E->Weight;//将V1插入V2的表头 //NewNode->Next = Graph->G[E->V2].FirstEdge;//Graph->G[E->V2].FirstEdge = NewNode;
}LGraph BuildGraph()
{LGraph Graph;Edge E;Vertex V;int Nv, i;cin >> Nv; //读入顶点个数 Graph = CreateGraph(Nv); //初始化有Nv个顶点但没有边的图 cin >> Graph->Ne; //读入边数 if (Graph->Ne != 0) { //如果有边 E = (Edge)malloc(sizeof(struct ENode)); //建立边结点 //读入边,格式为"起点 终点 权重",插入邻接矩阵 for (i = 0; i<Graph->Ne; i++) {cin >> E->V1 >> E->V2 >> E->Weight;//E->V1--;//E->V2--;//注意:如果权重不是整型,Weight的读入格式要改 InsertEdge(Graph, E);}}//如果顶点有数据的话,读入数据 //for (V = 0; V<Graph->Nv; V++)//cin >> Graph->G[V].Data;return Graph;
}//返回最大的元素
Vertex getMaxElement(Vertex arr[],int N) {Vertex maxElement = 0;for (int i = 0; i < N; i++)if (maxElement < arr[i])maxElement = arr[i];return maxElement;
}//邻接表存储 - 拓扑排序算法
bool TopSort(LGraph Graph, Vertex TopOrder[])
{ //对Graph进行拓扑排序, TopOrder[]顺序存储排序后的顶点下标 int Indegree[MaxVertexNum], cnt;Vertex V;PtrToAdjVNode W;//初始化Indegree[] for (V = 0; V<Graph->Nv; V++)Indegree[V] = 0;//遍历图,得到Indegree[] for (V = 0; V<Graph->Nv; V++)for (W = Graph->G[V].FirstEdge; W; W = W->Next)Indegree[W->AdjV]++; //对有向边<V, W->AdjV>累计终点的入度 //将所有入度为0的顶点入列 for (V = 0; V < Graph->Nv; V++)if (Indegree[V] == 0)myQueue.push(V);//下面进入拓扑排序 cnt = 0;while (!myQueue.empty()) {V = myQueue.front(); //弹出一个入度为0的顶点 myQueue.pop();TopOrder[cnt++] = V; //将之存为结果序列的下一个元素 //对V的每个邻接点W->AdjV for (W = Graph->G[V].FirstEdge; W; W = W->Next) {if (--Indegree[W->AdjV] == 0)//若删除V使得W->AdjV入度为0 myQueue.push(W->AdjV); //则该顶点入列 if ((Earliest[V] + W->Weight)>Earliest[W->AdjV]) {Earliest[W->AdjV] = Earliest[V] + W->Weight;}}} //while结束if (cnt != Graph->Nv)return false; //说明图中有回路, 返回不成功标志 elsereturn true;
}
int main(void) {LGraph myGraph = BuildGraph();Vertex TopOrder[MaxVertexNum];bool flag = TopSort(myGraph, TopOrder);Vertex showestTime = getMaxElement(Earliest, myGraph->Nv);if (true == flag) {cout << showestTime;}else {cout << "Impossible";}system("pause");return 0;
}
测试结果:
算法 图8 How Long Does It Take相关推荐
- 深度搜索和广度搜索领接表实现_数据结构与算法--图的搜索(深度优先和广度优先)...
数据结构与算法--图的搜索(深度优先和广度优先) 有时候我们需要系统地检查每一个顶点或者每一条边来获取图的各种性质,为此需要从图的某个顶点出发,访遍图中其余顶点,且使得每一个顶点只被访问一次,这个过程 ...
- 数据结构与算法--图的表示与常用算法
什么是图? 图(Graph)形结构中,是一种非线性结构,在图中每一个元素都可以有0或多个前驱,也可以有多个后驱.节点之间的关系是任意的,即图中任意两个数据元素之间都有可能相关. 图的术语 顶点:带有数 ...
- c语言 迷宫深度遍历 算法,图的遍历迷宫生成算法浅析
1. 引言 在平常的游戏中,我们常常会碰到随机生成的地图.这里我们就来看看一个简单的随机迷宫是如何生成. 2. 迷宫描述随机生成一个m * n的迷宫,可用一个矩阵maze[m][n]来表示,如图: ...
- 计算机基础知识数据结构与算法,(计算机基础知识)[数据结构与算法] 图
第六章 图 6.1 图的定义和基本术语 图: G=(V,E) Graph = (Vertex, Edge) V: 顶点(数据元素)的有穷非空集合 E: 边的有穷集合 完全图: 任意两个点都有一条边相连 ...
- c++ 遍历所有点且距离最短_编程小白暑期进阶笔记41-C语言数据结构与算法图遍历的应用...
基于广度优先遍历算法的应用 思考题: (思考题答案: BFS(广度优先遍历)在一般的带权图中是不能解决最短路问题,了解BFS的都知道,BFS是根据节点到源节点之间的节点数遍历的,也就是先访问离源节点节 ...
- 最短路径——迪杰斯特拉算法——图的数据结构
最短路径是在工程上经常用到的概念,在这里给出了从单源点到任意顶点的迪杰斯特拉算法. 先来看看基本概念: 用代码C语言实现如下: #include<string.h>#include< ...
- 图论算法——图的遍历
图论算法也是非常基础且重要的算法(ps:好像没有不重要的......) 图的基本应用--图的遍历,从具体的题目着手,学习图的遍历方式及代码形式. 我们先来看一下题目,然后再具体分析图的遍历方式. 题目 ...
- Python 数据结构与算法——图(Graph)
图结构(Graph)--算法学中最强大的框架之一.树结构只是图的一种特殊情况. 如果我们可将自己的工作诠释成一个图问题的话,那么该问题至少已经接近解决方案了.而我们我们的问题实例可以用**树结构(tr ...
- java数据结构和算法——图的深度优先(DFS)遍历
目录 一.图的遍历介绍 二.图的深度优先搜索(Depth First Search) 三.图的深度优先遍历算法步骤 四.图的深度优先遍历示例需求 五.图的深度优先遍历代码示例 一.图的遍历介绍 所谓图 ...
- java数据结构和算法——图的广度优先(BFS)遍历
目录 一.图的遍历介绍 二.图的广度优先搜索(Broad First Search) 三.图的广度优先遍历算法步骤 四.图的广度优先遍历示例需求 五.图的广度优先遍历代码示例 一.图的遍历介绍 所谓图 ...
最新文章
- LeNet5,AlexNet,MobileNet它们的前身你知道吗?
- 【Linux】Linux基本命令扫盲【转】
- Linux查看进程和进程管理
- 计算机组成原理第7章-输入/输出系统
- Intel Realsense D435 python (Python Wrapper)example -1: quick start (快速开始)
- 什么是 SAP Commerce Cloud 的 catalog
- MaxCompute印尼开服,成为阿里云第十二个大数据服务节点
- Leetcode836.Rectangle Overlap矩阵重叠
- 交互系统的构建之(一)重写Makefile编译TLD系统
- 30天敏捷结果(1):总体认识Getting Result敏捷方法
- vaex 处理海量数据_爱了爱了!0.052 秒打开 100GB 数据,这个Python开源库火爆了!...
- 百行征信出首招,发布授信 反欺诈 核验三款测试产品
- qqkey获取原理_征途手机版电脑版安装使用教程【安卓+ios电脑版图文攻略】
- 介绍几款在线脑图和流程图制作工具
- mysql 通过经纬度查询附近的地点位置
- React + TS项目开发小技巧总结
- 解决运行python脚本报错:ModuleNotFoundError: No module named ‘numpy‘
- 明确人生的目的和意义
- 国企计算机职称考试都考什么,计算机软考证书哪个含金量高?长什么样?国企有用吗?可以评职称吗?...
- php redis brpoplpush,Redis Brpoplpush 命令 - Redis 教程 - 自强学堂
热门文章
- Windows Server 2019 配置DHCP
- runtime error python 3.5_Python 3.5 RuntimeError: can't start new thread
- 坦克大战游戏c语言,C语言开发坦克大战游戏
- blowfish java_blowfish加密算法
- zblog火车头采集经验
- u-boot-1.1.6源码分析
- 【微信小程序入门到精通】— AppID和个性配置你学会了么?
- Linux#Shell#if [ $# -ne 1 ];then 是什么意思?
- Js学习心得和思考方法
- css 页面缩放边框产生空隙相关