PTA 08-图8 How Long Does It Take(25 分)

本文介绍了一种通过拓扑排序算法来确定项目最早完成时间的方法。针对给定的所有活动及其关系,利用图论中的概念,如节点、边、权重等,实现了一个C++程序来找出项目的最早可能完成时间。该程序特别注意了可能存在的多个结束节点和更新最早开始时间的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

08-图8 How Long Does It Take(25 分)

题目地址:08-图8 How Long Does It Take(25 分)
题目描述:

Given the relations of all the activities of a project, you are supposed to find the earliest completion time of the project.

  • 输入格式:
    Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of activity check points (hence it is assumed that the check points are numbered from 0 to N−1), and M, the number of activities. Then M lines follow, each gives the description of an activity. For the i-th activity, three non-negative numbers are given: S[i], E[i], and L[i], where S[i] is the index of the starting check point, E[i] of the ending check point, and L[i] the lasting time of the activity. The numbers in a line are separated by a space.

  • 输出格式:
    For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output “Impossible”.


Tips:
这题考查的是拓扑排序。会写拓扑排序应该没问题,但是有两个易错点需要注意:
1. 最终完工时间未必是最后一个结点完成的时间,因为可能有多个“结束结点”,最终的完成时间取决于这些结点中时间最长的一个。
2. 我在下面程序中做了标记(########),在我标记的for循环内,千万不要拿来更新EarlyVertexNum,我一开始就是这么写的,结果有两个测试样例通不过,我来我想了一下,如果对题目给的输入样例以来说,倒着输结点之间的权重,更新就会出问题。


程序:

#include <iostream>
#include <queue>
#include <cstdlib>
#include <cstdio>
using namespace std;

#define MaxVertexNum 105
typedef int WeightType;
typedef int Vertex;
int EarlyStart[MaxVertexNum] = {0};

/* 边定义 */
typedef struct ENode* Edge;
struct ENode
{
    Vertex V1, V2;
    WeightType Weight;
};

/* 邻接点定义 */
typedef struct AdjNode* PtrToAdjNode;
struct AdjNode
{
    Vertex AdjV;    // 邻接点下标
    WeightType Weight;
    PtrToAdjNode next;  
};

/* 顶点表头结点定义*/
typedef struct VNode
{
    PtrToAdjNode FirstEdge;
}AdjList[MaxVertexNum];

typedef struct GNode* LGraph;
struct GNode
{
    int Nv;     // 顶点数
    int Ne;     // 边数
    AdjList G;  
};

void InsertEdge(Edge E, LGraph Graph)
{   /* 头插法 插入边<V1, V2> */
    PtrToAdjNode NewNode = (PtrToAdjNode)malloc(sizeof(AdjNode));
    NewNode->AdjV = E->V2;
    NewNode->Weight = E->Weight;
    NewNode->next = Graph->G[E->V1].FirstEdge;
    Graph->G[E->V1].FirstEdge = NewNode;
}

LGraph InitialGraph(int Nv)
{   /* 初始化图 */
    LGraph Graph = (LGraph)malloc(sizeof(GNode));
    Graph->Nv = Nv;
    Graph->Ne = 0;
    for (int i = 0; i < Nv; i++)
        Graph->G[i].FirstEdge = NULL;
    return Graph;
}

LGraph BuildGraph(LGraph Graph)
{   /* 建立边联系 */
    cin >> Graph->Ne;
    for (int i = 0; i < Graph->Ne; i++)
    {
        Edge E = (Edge)malloc(sizeof(ENode));
        cin >> E->V1 >> E->V2 >> E->Weight;
        InsertEdge(E, Graph);
    }
    return Graph;
}

bool TopSort(LGraph Graph)
{   /* 拓扑排序 */
    int Indegree[MaxVertexNum] = {0}, cnt = 0;  // 初始化入度
    PtrToAdjNode W;
    for (int i = 0; i < Graph->Nv; i++)
    {
        for (W = Graph->G[i].FirstEdge; W; W = W->next) /* ########################## */
            Indegree[W->AdjV]++;    // 入度+1
    queue <Vertex> Q;
    for (Vertex V = 0; V < Graph->Nv; V++)
    {   /* 将入度为0的结点下标放入队列 */
        if (Indegree[V] == 0)
            Q.push(V);
    }
    while (!Q.empty())
    {
        Vertex V = Q.front();
        Q.pop();
        cnt++;  // 每出队一个元素cnt+1
        for (W = Graph->G[V].FirstEdge; W; W = W->next)
        {
            if (EarlyStart[W->AdjV] < W->Weight + EarlyStart[V])    // 更新最早开工时间
                EarlyStart[W->AdjV] = W->Weight + EarlyStart[V];
            Indegree[W->AdjV]--;    // 把所有的前驱结点为V的顶点的入度-1
            if (Indegree[W->AdjV] == 0)
                Q.push(W->AdjV);
        }
    }
    if (cnt != Graph->Nv)
        return false;
    else
        return true;
}

int main(int argc, char const *argv[])
{
    int N;
    cin >> N;
    LGraph Graph = InitialGraph(N);
    Graph = BuildGraph(Graph);
    if (!TopSort(Graph))
        cout << "Impossible" << endl;
    else
    {
        int Max = 0;
        for (int i = 0; i < N; i++) // 因为最长时间不一定在最后一个点
            if (EarlyStart[i] > Max)
                Max = EarlyStart[i];
        cout << Max << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值