关键路径、拓扑排序(学习记录)

偏序: (a、b、c代表顶点,R代表关系,aRb表示a到b有路径存在)
1.自反的—对于每一个顶点都有aRa(忽略)
2.反对称的—对于任意两个顶点a、b,aRb和bRa不能同时存在,即a到b有路径,b到a就不能有路径
3.传递的—aRb、bRc则,必有aRc 全序:任取两个顶点,a、b,必有aRb或bRa的偏序,即对于任两个顶点都有先后关系的偏序
拓扑排序:图是偏序的,由此输出的排序是全序的(AOV,顶点表示活动,弧表示优先关系的有向图)

方法:任取入度为0的点输出,然后去掉这个点,与这个点关联的点入度-1,循环直至所有点输出(成功),或者出现环结束(失败)

AOE网:弧表示活动,顶点表示事件,权表示活动持续时间
关键路径:路径最长的那段路径叫关键路径
4个辅助:(e(i-j)==l(i-j)为关键路径)
ve(i)事件i的最早发生时间
vl(i)事件i的最迟发生时间
e(i-j)活动最早发生时间(明显等于e(i))
l(i-j) 活动最晚发生时间(明显等于l(j)-dut<I,j>)
显然:

ve(j)=max{ve(i)+dut<I,j>}
vl(i)=min{vl(j)-dut<I,j>}
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int N, M;

struct ArcNode {//弧节点
    int ft;
    int tim;
    int nt;
    ArcNode *next;
    ArcNode() { next = NULL; }
};
struct VNode {//顶点节点
    string data;
    ArcNode *first;
    VNode() { first = NULL; }
};
struct Graph {
    vector<VNode> V;//顶点
    vector<ArcNode> A;//弧节点
    vector<int> Indegree;//入度
    vector<int> ve;//事件最早发生时间
    vector<int> vl;//事件最晚发生时间
};
Graph G;
int find_index(string a)//顶点名称对应的顶点位置
{
    for (int t = 0;t < N;t++)
        if (G.V[t].data == a) return t;
    cout << "ERROR" << endl;
    exit(0);
    return -1;
}
void CreateGraph(Graph &G)
{
    cout << "请输入顶点个数" << endl;
    cin >> N;
    cout << "请输入弧的数量" << endl;
    cin >> M;
    G.A.resize(M);G.V.resize(N);
    cout << "请依次输入顶点的名称,名称之间用空格隔开" << endl;
    for (int t = 0;t < N;t++)
        cin >> G.V[t].data;
    cout << "请依次输入弧的尾顶点 头顶点 弧长" << endl;
    vector<ArcNode *>  temp(N, NULL);//指向每个顶点的末尾
    G.Indegree.resize(N);
    for (int t = 0;t <M;t++)//用邻接表结构创建图
    {
        string a, b;
        int t_a, t_b, c;
        cin >> a >> b >> c;
        G.A[t].tim = c;
        t_a = find_index(a);
        t_b = find_index(b);
        G.A[t].ft = t_a;
        G.A[t].nt = t_b;
        G.Indegree[t_b]++;
        if (G.V[t_a].first == NULL)
            temp[t_a] = G.V[t_a].first = &G.A[t];
        else
            temp[t_a] = temp[t_a]->next = &G.A[t];
    }
}

void Print_G(Graph &G)//中途检查用,忽略
{
    for (auto x : G.V)
    {
        cout << x.data << endl;
        ArcNode *p = x.first;
        while (p != NULL)
        {
            cout << p->nt << " ";
            p = p->next;
        }
        cout << endl;
    }
}
vector<int> Topu;//保存拓扑排序
bool TopuSort(Graph &G)//拓扑排序+关键路径求ve[i]
{
    G.ve.resize(N);
    vector<int> temp_Indegree(G.Indegree);
    vector<int> temp;//过程中使用的栈
    for (int t = 0;t < N;t++)
        if (temp_Indegree[t] == 0) temp.push_back(t);
    while (!temp.empty()) 
    {
        Topu.push_back(temp.back());//输出到栈Topu中 
        int j = temp.back();
        ArcNode *p = G.V[j].first;temp.pop_back();
        while (p != NULL)
        {
            if (--temp_Indegree[p->nt] == 0) temp.push_back(p->nt);
            if (G.ve[j] + p->tim>G.ve[p->nt]) G.ve[p->nt] = G.ve[j] + p->tim;//求ve[i]
            p = p->next;
        }
    }
    if (Topu.size() != G.V.size()) return false;
    return true;
}

bool CriticalPath(Graph &G)//计算vl[i],并输出最短路径
{
    if (!TopuSort(G)) return false;
    G.vl.assign(N, G.ve.back());
    while (!Topu.empty())//计算vl[i]
    {
        int j = Topu.back();
        ArcNode *p = G.V[j].first;Topu.pop_back();
        while (p != NULL)
        {
            if (G.vl[p->nt] - p->tim < G.vl[j])G.vl[j] = G.vl[p->nt] - p->tim;
            p = p->next;
        }
    }
    for (int t = 0;t < M;t++)//输出
    {
        int e = G.ve[G.A[t].ft], l = G.vl[G.A[t].nt]-G.A[t].tim;
        if (e == l) printf("关键路径:%s %s,花费时间%d\n", G.V[G.A[t].ft].data.c_str(), G.V[G.A[t].nt].data.c_str(), G.A[t].tim);
    }
}
int main()
{
    CreateGraph(G);
    CriticalPath(G);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值