12月5日周末总结

AOE网与关键路径

AOE网是一个带权的有向无环图。其中用顶点表示事件,弧表示活动,权值表示两个活动持续的时间。AOE网是以边表示活动的网。
关键路径是指在AOE网中从源点到汇点路径最长的路径。这里的路径长度是指路径上各个活动持续时间之和。在AOE网中,有些活动是可以并行执行的,关键路径其实就是完成工程的最短时间所经过的路径。关键路径上的活动称为关键活动。

时间发生时间

事件vi的最早发生时间:从源点到顶点vivi的最长路径长度,称为事件vi的最早发生时间,记作ve(i)。求解ve(i)可以从源点ve(0)=0开始,按照拓扑排序规则根据递推得到:
ve(i)=Max{ve(k)+len(<k,j>∈)|<k,j>T,1≤i≤n−1
事件vi的最晚发生时间:在保证整个工程完成的前提下,活动最迟的开始时间,记作vl(i)。z 求解vi的最早发生时间ve(i)的前提vl(n-1)=ve(n-1)下,从汇点开始,向源点推进得到:
vl(i)=Min{vl(k)−len(<i,k>)|<i,k>∈S,0≤i≤n−2

活动发生时间

活动的最早开工时间,即弧ak 的最早发生时间:
ee[i]=ve[k]
活动的最晚开工时间,即弧ak 的最晚发生时间,也就是不推迟工期的最晚开工时间:
el[i]=vl[i]-len<vk,vj>
参考代码(转载于 大道至简 AOE网络与关键路径(二)——实现)

#include<iostream>
using namespace std;
 
#define MAXN 100		//顶点个数最大值
#define MAXM 200		//边数的最大值
 
struct ArcNode
{
	int to, dur, no;	//边的另一个顶点、持续时间、活动序号
	ArcNode *next;
};
int n, m;				//顶点个数、边数
ArcNode *List1[MAXN];	//每个顶点的边链表表头指针(出边表)
ArcNode *List2[MAXM];	//每个顶点的边链表表头指针(入边表)
int count1[MAXN];		//各顶点的入度
int count2[MAXM];		//各顶点的出度
int Ee[MAXN];			//各事件的最早可能开始时间
int El[MAXN];			//各事件的最迟允许开始时间
int e[MAXM];			//各活动的最早可能开始时间
int L[MAXM];			//各活动的最迟允许开始时间
void CriticalPath()		//求关键路径
{
	//拓扑排序求Ee
	int i, j, k;
	int top1 = -1;
	ArcNode *temp1;
	memset(Ee, 0, sizeof(Ee));
	for(i = 0; i < n; i++)
		if(count1[i] == 0) { count1[i] = top1; top1 = i; }
	for(i = 0; i < n; i++)
	{
		if(top1 == -1) { printf("Network has a cycle!\n"); return; }
		else 
		{
			j = top1; top1 = count1[top1];
			temp1 = List1[j];
			while(temp1 != NULL)
			{
				k = temp1->to;
				if(--count1[k] == 0) { count1[k] = top1; top1 = k; }
				if(Ee[j]+temp1->dur > Ee[k]) Ee[k] = Ee[j] + temp1->dur;//有向边<j, k>
				temp1 = temp1->next;
			}
		}
	}
	//逆拓扑排序求El
	int top2 = -1;
	ArcNode *temp2;
	for(i = 0; i < n; i++)
	{
		El[i] = Ee[n-1];
		if(count2[i] == 0) { count2[i] = top2; top2 = i; }
	}
	for(i = 0; i < n; i++)
	{
		j = top2; top2 = count2[top2];
		temp2 = List2[j];
		while(temp2 != NULL)
		{
			k = temp2->to;
			if(--count2[k] == 0) { count2[k] = top2; top2 = k; }
			if(El[j]-temp2->dur < El[k]) El[k] = El[j] - temp2->dur;//有向边<k, j>
			temp2 = temp2->next;
		}
	}
	//求各活动的e[k]和L[k]
	memset(e, 0, sizeof(e)); memset(L, 0, sizeof(L));
	printf("The Critical activities are:\n");
	for(i = 0; i < n; i++)
	{
		temp1 = List1[i];
		while(temp1 != NULL)
		{
			j = temp1->to; k = temp1->no;	//有向边<i, j>
			e[k] = Ee[i]; L[k] = El[j] - temp1->dur;
			if(e[k] == L[k]) printf("a%d : %d->%d\n", k, i, j);
			temp1 = temp1->next;
		}
	}
}
int main()
{
	int i, u, v, w;	//循环变量、边的起点和终点
	scanf("%d%d", &n, &m);	//读入顶点个数和边数
	memset(List1, 0, sizeof(List1)); memset(List2, 0, sizeof(List2));
	memset(count1, 0, sizeof(count1)); memset(count2, 0, sizeof(count2));
	ArcNode *temp1, *temp2;
	for(i = 0; i < m; i++)
	{
		scanf("%d%d%d", &u, &v, &w);	//读入边的起点和终点
		count1[v]++;
		temp1 = new ArcNode;			//构造邻接表
		temp1->to = v; temp1->dur = w;
		temp1->no = i + 1; temp1->next = NULL;
		if(List1[u] == NULL) List1[u] = temp1;
		else { temp1->next = List1[u]; List1[u] = temp1; }
		count2[u]++;
		temp2 = new ArcNode;			//构造逆邻接表
		temp2->to = u; temp2->dur = w;
		temp2->no = i + 1; temp2->next = NULL;
		if(List2[v] == NULL) List2[v] = temp2;
		else { temp2->next = List2[v]; List2[v] = temp2; }
	}
	CriticalPath();
	for(i = 0; i < n; i++)				//释放边链表上各边结点所占用的存储空间
	{
		temp1 = List1[i]; temp2 = List2[i];
		while(temp1 != NULL) { List1[i] = temp1->next; delete temp1; temp1 = List1[i]; }
		while(temp2 != NULL) { List2[i] = temp2->next; delete temp2; temp2 = List2[i]; }
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,根据您的要求,我可以给您提供一个简单的实现方式。首先,您需要下载并安装 Node Time 模块,然后按照以下步骤进行操作: 1. 使用 moment-timezone 库创建起始时间和结束时间的 Moment 对象,设置时区为您所在的时区,代码如下: ```javascript const moment = require('moment-timezone'); moment.tz.setDefault('Asia/Shanghai'); // 设置时区为上海 const startTime = moment.tz('2023-05-31 00:00:00', 'YYYY-MM-DD HH:mm:ss'); const endTime = moment.tz('2023-06-05 23:59:59', 'YYYY-MM-DD HH:mm:ss'); ``` 2. 计算出两个期之间的天数,并将其转换为分钟数,代码如下: ```javascript const days = endTime.diff(startTime, 'days'); const minutes = days * 8 * 60; // 假设每个工作工作8小时,每小时60分钟 ``` 3. 排除周末和非工作时间,代码如下: ```javascript for (let i = 0; i < days; i++) { const currentDate = startTime.clone().add(i, 'days'); const dayOfWeek = currentDate.day(); // 获取当前期的星期几,0 表示周,1 表示周一,以此类推 if (dayOfWeek === 0 || dayOfWeek === 6) { // 如果是周末,则跳过 continue; } const workStartTime = currentDate.clone().hour(9).minute(0).second(0); // 设置工作开始时间为当天的 9 点 const workEndTime = currentDate.clone().hour(18).minute(0).second(0); // 设置工作结束时间为当天的 18 点 const lunchStartTime = currentDate.clone().hour(12).minute(0).second(0); // 设置午餐开始时间为当天的 12 点 const lunchEndTime = currentDate.clone().hour(13).minute(30).second(0); // 设置午餐结束时间为当天的 13 点 30 分 if (startTime.isSameOrBefore(workStartTime)) { // 如果起始时间早于当天的工作开始时间,则将起始时间设为当天的工作开始时间 startTime = workStartTime; } if (endTime.isSameOrAfter(workEndTime)) { // 如果结束时间晚于当天的工作结束时间,则将结束时间设为当天的工作结束时间 endTime = workEndTime; } if (startTime.isBetween(lunchStartTime, lunchEndTime)) { // 如果起始时间在午休时间段内,则将起始时间设为午休结束时间 startTime = lunchEndTime; } if (endTime.isBetween(lunchStartTime, lunchEndTime)) { // 如果结束时间在午休时间段内,则将结束时间设为午休开始时间 endTime = lunchStartTime; } if (startTime.isAfter(endTime)) { // 如果起始时间晚于结束时间,则跳过 continue; } const workMinutes = endTime.diff(startTime, 'minutes'); // 计算当天的工作时间 minutes += workMinutes; } ``` 4. 最后,返回计算结果,代码如下: ```javascript console.log(`时间差为 ${minutes} 分钟`); ``` 请注意,上述代码仅供参考,您可能需要根据实际情况进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值