数据结构暑期自学--MOOC浙江大学pta(7-11 关键活动)

题目链接

前言:

挺麻烦的,就是进行了两次拓扑排序,一个按照出度,一个按照入度。

关键点:

1、初始化和定义,先定义个出度入度数组,还有两个数组分别记录一个工作最早和最晚完成的时间

int Indegree[1000+10];
int Outdegree[1000+10];
int early[1000+10];
int last[1000+10];

接下来是初始化,early数组要来计算最早完成工作的时间,当一个工作能开始,说明其入度的结点工作已完成,那必然是取所有入度结点活动时间的最大值,因此early数组初始化为0(最小值)

if (early[k]+cost[k][i]>early[i])

 early[i] = early[k]+cost[k][i]; 

k指当前从队列中取出的结点,i为与k连接的结点,重点 :注意cost[i][k]和cost[k][i]是不同的,算early数组和最少完成时间,用的是入度,因此用的是cost[k][i],再计算新的i结点的入度。。。

对于last数组的初始化,首先要明确last数组有什么用,last数组来计算该活动是否为关键活动

那么首先要明确关键活动的概念

关键活动指一刻都不能耽搁的活动,因此我们从最早完成的时间来倒着推,

if (last[i]>last[k]-cost[i][k])
last[i] = last[k]-cost[i][k];

因此每次要取最小指,last数组初始化为最大值。 

2、如何算最小值和如何判断是否可以完成工作

7-12 How Long Does It Take

3、 如何输出所有关键活动:

利用last数组和early数组,首先根据出度为0的点,要先初始化赋值该结点的last为最短完成的时间

,方便后序倒推

for (int i=1; i<=n; i++)
	{
		if (Outdegree[i]==0)
		{
			AddQ(Q, i);
			last[i] = time;
		}
	} 

最后是如何判断:

 if (last[j]-cost[i][j]-early[i]==0)
printf("%d->%d\n", i, j); 

如果当前结点的最晚完成时间与所连接的点的最早完成时间,相差刚刚好等于活动要完成的时间,那么说明该活动是一刻都不能耽搁。 

4、其实两步利用出度和入度进队列都差不多用法

完整代码:

# include <stdio.h>
# include <stdlib.h>
# define INF 100000
int n, m, totalcost;
int cost[1000+10][1000+10];
int Indegree[1000+10];
int Outdegree[1000+10];
int early[1000+10];
int last[1000+10];
typedef struct queue *Queue;
struct queue{
	int *data;
	int front, rear;
};
Queue CreateQueue(int size)
{
	Queue Q = (Queue)malloc(sizeof(struct queue));
	Q->data = (int *)malloc(sizeof(int)*size);
	Q->front = -1;
	Q->rear = -1;
	return Q;
}
void AddQ(Queue Q, int x)
{
	Q->data[++Q->rear] = x;
}
int DeleteQ(Queue Q)
{
	return Q->data[++Q->front];
}
int IsEmpty(Queue Q)
{
	if (Q->front==Q->rear)
	return 1;
	else
	return 0;
} 
void print(int time)
{
	Queue Q = CreateQueue(2000);
	for (int i=1; i<=n; i++)
	{
		if (Outdegree[i]==0)
		{
			AddQ(Q, i);
			last[i] = time;
		}
	} 
	while (!IsEmpty(Q))
	{
		int k = DeleteQ(Q);
		for (int i=1; i<=n; i++)
		{
			if (cost[i][k]<INF)
			{
				if (--Outdegree[i]==0)
				AddQ(Q, i);
				if (last[i]>last[k]-cost[i][k])
				last[i] = last[k]-cost[i][k];
			}
		}
	}
	for (int i=1; i<=n; i++)
	{
		for (int j=n; j>=1; j--)
		{
			if (cost[i][j]<INF)
			{
				if (last[j]-cost[i][j]-early[i]==0)
				printf("%d->%d\n", i, j);
			}
		}
	}
}
void Topsort()
{
	Queue Q = CreateQueue(2000);
	int cnt = 0;
	for (int i=1; i<=n; i++)
	{
		if (Indegree[i] == 0)
		AddQ(Q, i);
	}
	while (!IsEmpty(Q))
	{
		int k = DeleteQ(Q);
		cnt++;
		for (int i=1; i<=n; i++)
		{
			if (cost[k][i]<INF)
			{
				if (--Indegree[i]==0)
				AddQ(Q, i);
				if (early[k]+cost[k][i]>early[i])
				early[i] = early[k]+cost[k][i];
				if (early[i]>totalcost)
				totalcost = early[i];
			}
		}
	}
	if (cnt<n)
	{
		printf("0");
		return ;
	}
	else
	{
		printf("%d\n", totalcost);
		print(totalcost);
	}
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++)
	{
		Indegree[i] = 0;
		Outdegree[i] = 0;
		early[i] = 0;
		last[i] = INF;
		for (int j=1; j<=n; j++)
		cost[i][j] = INF;
	} 
	for (int i=1; i<=m; i++)
	{
		int x, y, cos;
		scanf("%d%d%d", &x, &y, &cos);
		cost[x][y] = cos;
		Indegree[y]++;
		Outdegree[x]++;
	}
	Topsort();
	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值