2021-04-25

08-图9 关键活动 (30 分)

假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。

比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和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<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define INFINITY 999
struct Graph {//有向图
	int** G;//每个过程的时间
	int Nv;
	int Ne;
	int* Data;//装有每个检查点的Ealiest
	int* InDegree;//入度
	int* OutDegree;
	int* StartPoints;
	int* StopPoints;

};
typedef struct Graph* MyGraph;
typedef int ElementType;
struct QNode {
	ElementType* Data;
	int Front;
	int Rear;
	int MaxSize;

};
typedef struct QNode* Queue;
Queue CreateQueue(int n);
bool IsFull(Queue Q);
bool IsEmpty(Queue Q);
bool InsertElement(Queue Q, ElementType Item);
ElementType OutQueue(Queue Q);
MyGraph CreateGraph(int VertexNum);
void InitializeGraph(MyGraph Graph, int EdgeNum);
bool TopSort(MyGraph Graph);
int FindMax(int* a, int n);
int main()
{
	int N, M;
	int Max;
	scanf("%d %d", &N, &M);
	MyGraph Graph = CreateGraph(N);
	InitializeGraph(Graph,M);
	if (TopSort(Graph))
	{
		Max = FindMax(Graph->Data, N);
		printf("%d", Max);
	}
	else
		printf("Impossible");

}
Queue CreateQueue(int n)
{
	Queue Q = (Queue)malloc(sizeof(struct QNode));
	Q->Data = (ElementType*)malloc(sizeof(ElementType) * n);
	Q->Front = 0;
	Q->Rear = 0;
	Q->MaxSize = n;
	return Q;
}
bool IsFull(Queue Q)
{
	return((Q->Rear + 1) % Q->MaxSize == Q->Front);
}
bool IsEmpty(Queue Q)
{
	return(Q->Front == Q->Rear);
}
bool InsertElement(Queue Q,ElementType Item)
{
	if (!IsFull(Q))
	{
		Q->Rear = (Q->Rear + 1) % Q->MaxSize;
		Q->Data[Q->Rear] = Item;
		return true;
	}
	else
		return false;
}
ElementType OutQueue(Queue Q)
{
	if (!IsEmpty(Q))
	{
		Q->Front = (Q->Front + 1) % Q->MaxSize;
		return Q->Data[Q->Front];
	}
	else
		return -1;
}
MyGraph CreateGraph(int VertexNum)
{
	MyGraph Graph = (MyGraph)malloc(sizeof(struct Graph));
	Graph->G = (int**)malloc(sizeof(int*) * VertexNum);
	for (int i = 0; i < VertexNum; i++)
	{
		Graph->G[i] = (int*)malloc(sizeof(int) * VertexNum);
	}
	Graph->Nv = VertexNum;
	Graph->InDegree = (int*)malloc(sizeof(int) * VertexNum);
	Graph->Data = (int*)malloc(sizeof(int) * VertexNum);
	Graph->OutDegree = (int*)malloc(sizeof(int) * VertexNum);
	Graph->StartPoints = (int*)malloc(sizeof(int) * VertexNum);
	Graph->StopPoints = (int*)malloc(sizeof(int) * VertexNum);
	return Graph;
}
void InitializeGraph(MyGraph Graph,int EdgeNum)
{
	int VertexA, VertexB, Weight;
	for (int i = 0; i < Graph->Nv; i++)
	{
		for (int j = 0; j < Graph->Nv; j++)
		{
			
				Graph->G[i][j] = INFINITY;
			
		}
		Graph->InDegree[i] = 0;
		Graph->Data[i] = 0;
		Graph->OutDegree[i] = 0;
		Graph->StartPoints[i] = 0;//0不是
		Graph->StopPoints[i] = 0;//0不是


	}
	for (int i = 0; i < EdgeNum; i++)
	{
		scanf("%d %d %d", &VertexA, &VertexB, &Weight);
		Graph->InDegree[VertexB] += 1;
		Graph->OutDegree[VertexA] += 1;
		Graph->G[VertexA][VertexB] = Weight;
	}
	for (int i = 0; i < Graph->Nv; i++)//寻找起始点和终点
	{
		if (Graph->InDegree[i] == 0)
		{
			Graph->StartPoints[i]= 1;
		}
		if (Graph->OutDegree[i] == 0)
		{
			Graph->StopPoints[i] = 1;
		}
	}
	Graph->Ne = EdgeNum;
}
bool TopSort(MyGraph Graph)
{
	int StartPoint;
	int CurrentPoint;
	int Cnt=0;
	Queue Q = CreateQueue(Graph->Nv + 10);
	for (int i = 0; i < Graph->Nv; i++)//寻找起始点
	{
		if (Graph->StartPoints[i] == 1)
		{
			StartPoint = i;
			InsertElement(Q, StartPoint);
			while (!IsEmpty(Q))
			{
				CurrentPoint = OutQueue(Q);
				Cnt++;
				for (int i = 0; i < Graph->Nv; i++)
				{
					if (Graph->G[CurrentPoint][i] != INFINITY)
					{
						Graph->InDegree[i]--;
						if (Graph->InDegree[i] == 0)
							InsertElement(Q, i);
						if (Graph->Data[i] < Graph->Data[CurrentPoint] + Graph->G[CurrentPoint][i])
						{
							Graph->Data[i] = Graph->Data[CurrentPoint] + Graph->G[CurrentPoint][i];
						}
					}
				}
			}
		}
	}
	if (Cnt < Graph->Nv)
	{
		return false;
	}
	else
		return true;

}
int FindMax(int* a, int n)
{
	int Max = a[0];
	for (int i = 1; i < n; i++)
	{
		if (Max < a[i])
			Max = a[i];
	}
	return Max;
}

拓扑排序对节点进行遍历(访问的是入度为空的节点)正好能得出关键路径节点的值

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
最新发布
06-03

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值