关键路径是以拓扑序列为基础的
用来解决类似:
事件的最早发生时间
事件的最晚发生时间
活动的最早发生时间
活动的最晚发生时间
(事件是结点 活动是边)
例题:p1113杂物
问题:可以用 dijkstra算法求最短距离来算来代替???
答 :一般不行,因为它的边代表的距离不能为负数。
但是上面那个题目好像可以用..
题解:
因为这个题目只告诉每个结点和需要完成它所需的先决条件
所以得用技巧把表建立成每个结点后面接着一连串连接它的结点的邻接表
dp[] 最短时间数组
tim[] 存时间
vector to[N] 存邻接表
rud[] 存入度的数组
#include <bits/stdc++.h>
using namespace std;
const int N=10010;
int n,t,tim[N],e;
int rud[N],dp[N],ans;
vector<int> to[N];
queue<int> q;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&t); //下标
scanf("%d",tim+t); //时间 tim数组中全是每个结点的耗时
scanf("%d",&e); //先决杂物
while(e!=0)
{
to[e].push_back(t); //重点:先决杂物充当下标 把真正的下标存入先决杂物后面
//vector存先决杂物
rud[t]++;
scanf("%d",&e);
}
}
for(int i=1;i<=n;i++)
if(!rud[i]) // 找到度为 0 的结点 并且全部入队列
{
q.push(i); // 入队列
dp[i]=tim[i]; //当 某个结点的入度等于零时 dp[i]最短耗时 = 每个结点耗时
}//处理开始时入度为0的点
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<to[now].size();i++)
{
int nex=to[now][i];
dp[nex]=max(dp[nex], dp[now]+tim[nex]);//如题
rud[nex]--;
if(rud[nex]==0)
q.push(nex);
}
}
for(int i=1;i<=n;i++)
ans=max(ans,dp[i]);//找 dp表里面的最大的数字
printf("%d\n",ans);
return 0;
}
首先理解:→拓扑序列←
通常我们把计划,施工过程,生产流程,顺序流程等当成一个工程,一个大的工程常常被划分为许多小的工程,这些子工程被称为活动,当这些工程完成时,整个工程也就完成了。
《《《《《《《《《《 储存方式为邻接矩阵 《《《《《《《《《《《
//b[]为每个点的入度
for(i=1;i<=n;i++) //因为有 n个结点 所以循环 n次。。
{
for(j=1;j<=n;j++) // 遍历下存入度的结点
{
if(b[j]==0)
{
//找到一个入度为 0的点
ans=j;
vis[cnt++]=j; // 记下已经排出来的字母
b[j]--; //这个点退出图 变成 -1
break;
}
}
for(j=1;j<=n;j++)
if(a[ans][j]) b[j]--; //与入度为 0的点相连的点的入度减一
}
printf("%d",vis[0]); //如果当图只有一个结点 不这样写cnt就为 1,什么也输出不了
for(i=1;i<cnt;i++) printf(" %d", vis[i]);
printf("\n");
这是上面理解中简单理解但效率不高的方法
再理解:→关键路径←
ve [k] : 事件最早发生的时间
v l [k] : 事件最晚发生的时间
e[i] : 活动最早发生的时间
l[i] : 活动最晚发生的时间
1.事件最早发生的时间
ve[1] = 0;
ve[k] = max{ve[j] + len<vj, vk>}; (<vj, vk> 属于 p[k])
2.事件最晚发生的时间:从后往前来的,必须知道终点的最早发生时间且讲它作为起点
vl[k] = max{vl[[j] - len<vk, vj>};
注:在知道最早和最晚后通过公式可得到活动的最早最晚发生的时间:
3.活动最早发生的时间:
e[i] = ve[k];
4.活动最晚发生的时间
l[i] = vl[j] - len<vk, vj>;