关键路径

[复制链接]
发表于 2024-1-2 18:05:19 | 显示全部楼层 |阅读模式
AOE网(Activity on Edge):它是一个带权的有向无环图,可用来估算工程的完成时间。
以下图为例。绿色的0叫做源点,红色的7叫做汇点;其他的每一个点都叫做一个事件;一条边叫做一项活动,权代表活动持续的时间。

其中,路径最长的路径叫做关键路径,影响工程进度的活动叫关键活动,并且关键路径上的活动一定是关键活动。
最早开工时间和最晚开工时间相等的工程是关键活动。
【问题描述】假设以AOE网表示一个施工流程图,弧上的权值表示完成该项子工程所需的时间。求:
① 完成整个工程的最短时间;
② 在满足依赖关系,并且不影响最短时间的前提下,每项工程的最早开工时间和最晚开工时间;
③ 关键路径
问题①、③以问题②为基础,比较容易实现。所以下面两个程序将解决问题②。
(1) 对DAG求关键路径  [邻接矩阵/邻接表]
这是DAG上的动态规划。注意,只有图的拓扑排序序列为0,1,2,……时才能用这种算法!
1. 状态表示:设 f(i)为事件 i 的最早开工时间,g(i)为事件 i 的最晚开工时间。
2. 状态转移方程:
f(i)=min{f(j)+G[j][i]} g(j)=min{g(j)-G[j][i]} 其中 j i 的前趋。
3. 边界条件:f(0)=0,g(n)=f(n-1)
4. 计算时先顺推出 f(n),然后令 g(n)=f(n),再倒推出 g(0)。如果关键路径通过点 i,则 f(i)=g(i)。
f[0]=0;
for (int i=1; i<=n; i++)
{
int max=0;
for (int j=0; j<=n; j++)
if (G[j]!=INF)   if (G[j]+f[j]>max) max=G[j]+f[j]; f=max;
}
g[n]=f[n]; for (int i=n-1; i>=0; i--)
{  int min=INF;  for (int j=0; j<=n; j++)   if (G[j]!=INF)    if (g[j]-G[j]<min) min=g[j]-G[j];  g=min;
}
// 寻找关键路径
for (int i=1; i<n; i++) if (et==eet) cout<<i<<"->"; cout<<n;
(2) 对拓扑序列求关键路径  [邻接矩阵]
这仍然需要动态规划。
1. 划分阶段:以拓扑序列划分阶段,一项工程为一个阶段。
2. 状态表示:设 f(i)为事件 i 的最早开工时间,g(i)为事件 i 的最晚开工时间。
3. 状态转移方程:
f(i)=min{f(j)+G[j][i]} g(j)=min{g(j)-G[j][i]} 其中 ji。由于序列由拓扑排序产生,j要么是i的前趋,要么和i无依赖关系。计算时先顺推出 f(n),然后令 g(n)=f(n),再倒推出 g(0)。
#include <iostream> #include <cstring> using namespace std;
const int INF=100000000, N=10000; int G[N][N];
int a[N];    // 拓扑排序序列
int f[N],g[N],prev[N]; int n,m;
bool topsort();  // 拓扑排序,代码见153页,但是所有<n”要改成“<=n”。
void print(int i)
{  if (i==-1) return;  print(prev);  cout<<i<<" ";
}


int main()
{  cin>>n>>m;  for (int i=0; i<=n; i++)   for (int j=0; j<=n; j++)    G[j]=INF;
for (int i=1; i<=m; i++)
{
  int u,v,w;   cin>>u>>v>>w;
  G[v]=w;
}
memset(f,0,sizeof(f));  memset(g,0,sizeof(g));  memset(prev,-1,sizeof(prev));  if (!topsort()) return 0;
  for (int i=1; i<=n; i++)   for (int j=0; j<i; j++)
  {
   int &x=a[j], &y=a;    if (G[x][y]!=INF && f[y]<f[x]+G[x][y])
   {
    f[y]=f[x]+G[x][y];     prev[y]=x;
   }
  }
g[n]=f[n];  for (int i=n-1; i>=0; i--)   for (int j=n; j>i; j--)
  {
   int &x=a[j], &y=a;    if (G[y][x]!=INF && g[y]<g[x]-G[y][x])     g[y]=g[x]-G[y][x];
  }
  cout<<"Len="<<f[a[n]]<<endl;  print(a[n]);  return 0;
}

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表