1-1
分数 10
作者 周强
单位 青岛大学
若图G为连通图且不存在拓扑排序序列,则图G必有环。
T
若图G有环,则G不存在拓扑排序序列。
分数 10
作者 魏宝刚
单位 浙江大学
如果从有向图 G 的每一点均能通过深度优先搜索遍历到所有其它顶点,那么该图一定不存在拓扑序列。
T
如果从有向图 G 的每一点均能通过深度优先搜索遍历到所有其它顶点,则该图是一个有环图;而拓扑排序的前提是有向无环图;
分数 5
作者 DS课程组
单位 浙江大学
对下图进行拓扑排序,可以得到不同的拓扑序列的个数是:
A.4
B.3
C.2
D.1
a没有被其他节点指向;
d没有指向其他节点;
所以拓扑排序的形式如下:aXXXd;
又因为b指向c,那么b一定是在c的前面;
所以可能的拓扑排序如下:
abced,aebcd,abecd;
分数 5
作者 DS课程组
单位 浙江大学
在拓扑排序算法中用堆栈和用队列产生的结果会不同吗?
A.是的肯定不同
B.肯定是相同的
C.有可能会不同
D.以上全不对
使用堆栈最后从栈顶到栈底就是逆拓扑的有序序列,而使用队列就是正拓扑的有序序列。
实际上使用堆栈形成的类似于dfs,而使用队列形成的类似于bfs
使用堆栈形成的会将一系列相关的结点存放在一起。
分数 5
作者 陈越
单位 浙江大学
下图为一个AOV网,其可能的拓扑有序序列为:
A.ABCDFEG
B.ADFCEBG
C.ACDFBEG
D.ABDCEFG
有时,给出一个 n 个点 m 条边的有向图,需要判定图是否是 AOV 网,也即判断图是否可以进行拓扑排序。
一个有向图无法进行拓扑排序时只有一种情况:该有向图中存在环。
分数 5
作者 考研真题
单位 浙江大学
下列选项中,不是如下有向图的拓扑序列的是:
A.1, 5, 2, 3, 6, 4
B.5, 1, 2, 6, 3, 4
C.5, 1, 2, 3, 6, 4
D.5, 2, 1, 6, 3, 4
分数 5
作者 考研真题
单位 浙江大学
修改递归方式实现的图的深度优先搜索(DFS)算法,将输出(访问)顶点信息的语句移动到退出递归前(即执行输出语句后立即退出递归)。采用修改后的算法遍历有向无环图 G,若输出结果中包含 G 中的全部顶点,则输出的顶点序列是 G 的:
A.拓扑有序序列
B.逆拓扑有序序列
C.广度优先搜索序列
D.深度优先搜索序列
使用堆栈最后从栈顶到栈底就是逆拓扑的有序序列,而使用队列就是正拓扑的有序序列。
实际上使用堆栈形成的类似于dfs,而使用队列形成的类似于bfs
使用堆栈形成的会将一系列相关的结点存放在一起。
分数 5
作者 陈越
单位 浙江大学
假设我们掌握了从各种不同案件中推导出的疑犯关系,即“A 与 B 属于同一团伙”的信息若干条,要求判断是否所有嫌犯都属于同一个团伙。以下哪种算法不能解决这个问题?
A.并查集
B.广度优先搜索
C.最小生成树算法
D.拓扑排序算法
分数 5
作者 考研真题
单位 浙江大学
下图所示的 AOE 网表示一项包含 8 个活动的工程。活动 d 的最早开始时间和最迟开始时间分别是:
A.3 和 7
B.12 和 12
C.12 和 14
D.15 和 15
一、概念
等式表示每个过程完成需要用掉的时间
最早开始时间用e(early?),最晚开始时间l(last?)
方法一,按每个节点计算
1.先计算节点最早开始时间,下个节点能开始,必须要前面的过程都完成,所以要取所有直线中的最大值(每个节点用时最长)。比如节点2,a和c+b都能到,用时最长的是c+b,最早开始时间要用c+b的和12。
2.计算节点最晚开始时间,要从最后一个节点倒过来向前做差,并且取所有支线中的最小值(不然过程更长的节点时间不够用)。
上图蓝色为最早开始时间,红色为最晚开始时间。
最早和最晚开始时间一致的:节点1、3、2、5,所以关键路径有2条,1356和13256。
方法二,按每个过程计算
a b c d e f g h 最长
e 0 8 0 12 12 8 19 18 (27)
l 9 8 0 14 12 8 21 18
计算过程:
一、计算最早开始时间e。
a和c都是最开始的,所以最早开始时间为0。
b要在c完成后才能开始,所以b的最早开始时间为8。
d要a、b都完成后才能开始,所以d的最早开始时间要看a和b谁完成需要的时间大。a只要0+3,b要0+8+4,所以d的最早开始时间为12。
其他同理。最终算出整个项目需要27才能完成。
二、计算最晚开始时间l。
从后往前计算
h的最晚开始时间是项目总时间-自己时间:27-9=18
g的最晚开始时间是项目总时间-自己时间:27-6=21
f的最晚开始时间是h的最晚时间-自己时间:18-10=8
e的最晚开始时间是h的最晚时间-自己时间:18-6=12
d的最晚开始时间是g的最晚时间-自己时间:21-7=14
b的最晚开始时间是d分支和e分支的最晚时间-自己时间,取最小值:d:14-4=10,e:12-4=8,所以是8
同理c的最晚时间是0,a的最晚时间是9
三、关键路径
bcefh的最早开始时间和最晚开始时间相等,所以他们是关键路径。看下图可知有cbeh和cfh两条。
分数 5
作者 考研真题
单位 浙江大学
下图是一个有 10 个活动的 AOE 网,时间余量最大的活动是:
A.c
B.g
C.h
D.j
解析:根据AOE网可得事件最早发生时间ve和最晚发生时间vl如下:
由此可知活动a,b,c,d,e,f,g,h,i,j时间余量分别为:2,0,0,4,0,2,6,2,4,0。时间余量最大的活动是g,选择B选项。
题目:
下列AOE网表示一项包含8个活动的工程。通过同时加快若干活动的进度可以缩短整个工程的工期。下列选项中,加快其进度就可以缩短工程工期的是()
A.c和e
B.d和e
C.f和d
D.f和h
该图的关键路径有:
bfh
bdeh
bdcg
这三条关键路径。同时减少关键路径上的时间,可以缩短整个工程的进度。只有C才能同时缩短这三条关键路径的时间。
.先找关键路径:使整个工程花时间最多的那条路径
答案选C。
关于缩短整个工程进度的问题:
缩短关键路径上的活动的进度可以缩短整个工程的进度。
所以同时缩短多条关键路径上的活动的进度可以缩短整个工程的进度。
7-1 任务调度的合理性
分数 15
作者 DS课程组
单位 浙江大学
假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。
比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和C程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如C程序设计和数据结构两门课,必须先学习前者。
但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务A依赖于子任务B,子任务B依赖于子任务C,子任务C又依赖于子任务A”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。你现在的工作是写程序判定任何一个给定的任务调度是否可行。
输入格式:
输入说明:输入第一行给出子任务数N(≤100),子任务按1~N编号。随后N行,每行给出一个子任务的依赖集合:首先给出依赖集合中的子任务数K,随后给出K个子任务编号,整数之间都用空格分隔。
输出格式:
如果方案可行,则输出1,否则输出0。
输入样例1:
12
0
0
2 1 2
0
1 4
1 5
2 3 6
1 3
2 7 8
1 7
1 10
1 7
输出样例1:
1
输入样例2:
5
1 4
2 1 4
2 2 5
1 3
0
输出样例2:
0
//拓扑排序 如果存在环则不能输出正常序列
#include <iostream>
#include <queue>
using namespace std;
queue<int> q;
void topology(int N)
{
int in, m, cnt = 0;
int Indegree[105] = {0}; //入度初始化为0
int son[105][105];
for (int i = 1; i <= N; i++)
{
cin >> in;
Indegree[i] = in;//将其入度存进去了
for (int j = 0; j < in; j++)
cin >> son[i][j];
}
for (int i = 1; i <= N; i++)
if (Indegree[i] == 0)
q.push(i);
while (q.size() != 0)
{
//将入度为0的出队
m = q.front();
q.pop();
cnt++;
for (int i = 1; i <= N; i++)
{
for (int j = 0; j < 105; j++)
{
if (son[i][j] == m)
{
Indegree[i]--;//入度减一
if (Indegree[i] == 0)//为0时入队
q.push(i);
}
}
}
}
if (cnt == N )
cout << 1;
else
cout << 0;
}
int main()
{
int N;
cin >> N;
topology(N);
}
7-2 关键活动
作者 DS课程组
单位 浙江大学
假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。
比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和C程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如C程序设计和数据结构两门课,必须先学习前者。
但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务A依赖于子任务B,子任务B依赖于子任务C,子任务C又依赖于子任务A”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。
任务调度问题中,如果还给出了完成每个子任务需要的时间,则我们可以算出完成整个工程需要的最短时间。在这些子任务中,有些任务即使推迟几天完成,也不会影响全局的工期;但是有些任务必须准时完成,否则整个项目的工期就要因此延误,这种任务就叫“关键活动”。
请编写程序判定一个给定的工程项目的任务调度是否可行;如果该调度方案可行,则计算完成整个工程项目需要的最短时间,并输出所有的关键活动。
输入格式:
输入第1行给出两个正整数N(≤100)和M,其中N是任务交接点(即衔接相互依赖的两个子任务的节点,例如:若任务2要在任务1完成后才开始,则两任务之间必有一个交接点)的数量。交接点按1~N编号,M是子任务的数量,依次编号为1~M。随后M行,每行给出了3个正整数,分别是该任务开始和完成涉及的交接点编号以及该任务所需的时间,整数间用空格分隔。
输出格式:
如果任务调度不可行,则输出0;否则第1行输出完成整个工程项目需要的时间,第2行开始输出所有关键活动,每个关键活动占一行,按格式“V->W”输出,其中V和W为该任务开始和完成涉及的交接点编号。关键活动输出的顺序规则是:任务开始的交接点编号小者优先,起点编号相同时,与输入时任务的顺序相反。
输入样例:
7 8
1 2 4
1 3 3
2 4 5
3 4 3
4 5 1
4 6 6
5 7 5
6 7 2
输出样例:
17
1->2
2->4
4->6
6->7
//拓扑排序 如果存在环则不能输出正常序列
#include <iostream>
#include <queue>
#include <algorithm>
#define N 103
using namespace std;
int indegree[N] = {0}, outdegree[N] = {0};
int e[N] = {0}, l[N] = {0};
int mp[N][N];
int maxx;
int TopologyAndGete(int n)
{
int m, cnt = 0;
queue<int> q;
for (int i = 1; i <= n; i++)
if (indegree[i] == 0)
q.push(i);
while (q.size() != 0)
{
//将入度为0的出队
m = q.front();
q.pop();
cnt++;
maxx = max(maxx, e[m]);
for (int i = 1; i <= n; i++)
{
if (mp[m][i] != 0)
{
e[i] = max(e[i], mp[m][i] + e[m]);
indegree[i]--;
if (indegree[i] == 0)
q.push(i);
}
}
}
return cnt == n;
}
void Getl(int n)
{
int m, cnt = 0;
queue<int> q;
for (int i = 1; i <= n; i++)
{
if (outdegree[i] == 0)
q.push(i);
l[i] = maxx;
}
while (q.size() != 0)
{
m = q.front();
q.pop();
cnt++;
for (int i = 1; i <= n; i++)
{
if (mp[i][m] != 0)
{
l[i] = min(l[i], l[m] - mp[i][m]);
outdegree[i]--;
if (outdegree[i] == 0)
q.push(i);
}
}
}
}
//最早开始时间和最晚开始时间相等,是关键路径
int main()
{
int n, m;
int x, y, t;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
cin >> x >> y >> t;
mp[x][y] = t;
outdegree[x]++;
indegree[y]++;
}
if (TopologyAndGete(n))
{
cout << maxx << endl;
Getl(n);
for (int i = 1; i <= n; i++)
{
if (e[i] != l[i])
continue;
for (int j = n; j >= 1; j--)
{
if (mp[i][j] && e[j] == l[j] && l[j] == e[i] + mp[i][j])
printf("%d->%d\n", i, j);
}
}
}
else
cout << 0;
}