前言:
挺麻烦的,就是进行了两次拓扑排序,一个按照出度,一个按照入度。
关键点:
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、如何算最小值和如何判断是否可以完成工作
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;
}