浙大数据结构第八周之08-图8 How Long Does It Take

news/2024/7/5 2:19:26

前置知识:

拓扑排序:

/* 邻接表存储 - 拓扑排序算法 */

bool TopSort( LGraph Graph, Vertex TopOrder[] )
{ /* 对Graph进行拓扑排序,  TopOrder[]顺序存储排序后的顶点下标 */
    int Indegree[MaxVertexNum], cnt;
    Vertex V;
    PtrToAdjVNode W;
    Queue Q = CreateQueue( Graph->Nv );
 
    /* 初始化Indegree[] */
    for (V=0; V<Graph->Nv; V++)
        Indegree[V] = 0;
        
    /* 遍历图,得到Indegree[] */
    for (V=0; V<Graph->Nv; V++)
        for (W=Graph->G[V].FirstEdge; W; W=W->Next)
            Indegree[W->AdjV]++; /* 对有向边<V, W->AdjV>累计终点的入度 */
            
    /* 将所有入度为0的顶点入列 */
    for (V=0; V<Graph->Nv; V++)
        if ( Indegree[V]==0 )
            AddQ(Q, V);
            
    /* 下面进入拓扑排序 */ 
    cnt = 0; 
    while( !IsEmpty(Q) ){
        V = DeleteQ(Q); /* 弹出一个入度为0的顶点 */
        TopOrder[cnt++] = V; /* 将之存为结果序列的下一个元素 */
        /* 对V的每个邻接点W->AdjV */
        for ( W=Graph->G[V].FirstEdge; W; W=W->Next )
            if ( --Indegree[W->AdjV] == 0 )/* 若删除V使得W->AdjV入度为0 */
                AddQ(Q, W->AdjV); /* 则该顶点入列 */ 
    } /* while结束*/
    
    if ( cnt != Graph->Nv )
        return false; /* 说明图中有回路, 返回不成功标志 */ 
    else
        return true;
}

题目详情:

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

Input Specification:

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.

Output Specification:

For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output "Impossible".

Sample Input 1:

9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4

Sample Output 1:

18

Sample Input 2:

4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5

Sample Output 2:

Impossible

简单翻译:

第i行实际上给出的是一条有向边的信息,包括这条边的起点,终点和权值,要求在对这些事件进行拓扑排序后找到完成这系列事件所需时间,暂未涉及到关键路径问题,不要想复杂

主要思路:

难点:

(一)如何建图

第i行实际上给出的是一条有向边的信息,包括这条边的起点,终点和权值

用邻接矩阵建图应该也可以,不过锻炼能力还是用邻接表建图

(二)如何遍历

拓扑排序

关键一:

Earliest的更新:Earliest[i]表示完成节点i所需的最早时间单位,但因为存在不同的依赖关系,所以在若干前置事件完成后必须从中挑出一个最大的

关键二:

不是vertexNums-1就是结束事件,而是要在Earliest数组中找到最大值

代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define MAX_NODE_NUMS 105
#define TRUE 1
#define FALSE 0
#define NONE -1
typedef int bool;
/*实现队列的数据结构*/
typedef struct QueueNode QueueNode;
typedef QueueNode* Queue;
struct QueueNode {
    int Head, Rear, Size;
    int Data[MAX_NODE_NUMS];
};
void InitQueue(Queue* q) {
    (*q)->Head = 0;
    (*q)->Rear = -1;
    (*q)->Size = 0;
    for(int i = 0; i < MAX_NODE_NUMS; i++) {
        (*q)->Data[i] = NONE;
    }
}
bool IsEmpty(Queue* q) {
    if((*q)->Size == 0) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
bool IsFull(Queue* q) {
    if((*q)->Size == MAX_NODE_NUMS) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
void Enqueue(Queue* q, int data) {
    if(!IsFull(q)) {
        (*q)->Data[((*q)->Rear + 1) % MAX_NODE_NUMS] = data;
        (*q)->Rear = ((*q)->Rear + 1) % MAX_NODE_NUMS;
        (*q)->Size++;
        return;
    }
}
int Dequeue(Queue* q) {
    if(!IsEmpty(q)) {
        int ret = (*q)->Data[(*q)->Head];
        (*q)->Head = ((*q)->Head + 1) % MAX_NODE_NUMS;
        (*q)->Size--;
        return ret;
    }
}
/*实现邻接表构造的图的数据结构*/ 
typedef struct EdgeNode EdgeNode;
typedef EdgeNode* PToEdge;
struct EdgeNode {
    int Start, End, Weight;
};
typedef struct AdjVNode AdjVNode;
typedef AdjVNode* PToAdjVNode;
struct AdjVNode {
    int Index;
    int Weight;
    PToAdjVNode Next;
};
typedef struct HeadNode HeadNode;
struct HeadNode {
    int Data;
    PToAdjVNode FirstEdge;
};
typedef struct ListGraphNode ListGraphNode;
typedef ListGraphNode* ListGraph;
struct ListGraphNode {
    int VertexNums, EdgeNums;
    HeadNode Head[MAX_NODE_NUMS];
};
ListGraph CreateEmptyGraph(int vertexNums) {
    ListGraph graph = (ListGraph)malloc(sizeof(ListGraphNode));
    graph->VertexNums = vertexNums;
    for(int i = 0; i < graph->VertexNums; i++) {
        graph->Head[i].FirstEdge = NULL;
    }
    return graph;
}
/*注意,这里插入的是有向边*/
void InsertEdge(PToEdge edge, ListGraph graph) {
    PToAdjVNode newNode = (PToAdjVNode)malloc(sizeof(AdjVNode));
    newNode->Index = edge->End;
    newNode->Weight = edge->Weight;
    newNode->Next = graph->Head[edge->Start].FirstEdge;
    graph->Head[edge->Start].FirstEdge = newNode;
    return;
}
ListGraph BuildGraph(int vertexNums, int edgeNums) {
    ListGraph graph = CreateEmptyGraph(vertexNums);
    graph->EdgeNums = edgeNums;
    for(int i = 0; i < edgeNums; i++) {
        PToEdge edge = (PToEdge)malloc(sizeof(EdgeNode));
        scanf("%d %d %d", &(edge->Start), &(edge->End), &(edge->Weight));
        InsertEdge(edge, graph);
        free(edge);
    }
    return graph;
}
int InDegree[MAX_NODE_NUMS];
int Earliest[MAX_NODE_NUMS];
void TopSort(ListGraph graph) {
    /*初始化*/
    for(int i = 0; i < graph->VertexNums; i++) {
        for(PToAdjVNode p = graph->Head[i].FirstEdge; p; p = p->Next) {
            InDegree[p->Index]++;
        }
    }

    Queue q = (Queue)malloc(sizeof(QueueNode));
    InitQueue(&q);
    int Vcount = 0;
    for(int i = 0; i < graph->VertexNums; i++) {
        if(InDegree[i] == 0) {
            Enqueue(&q, i);
            Earliest[i] = 0;
        }
    }   
    while(!IsEmpty(&q)) {
        int vertexIndex = Dequeue(&q);
        Vcount++;
        for(PToAdjVNode p = graph->Head[vertexIndex].FirstEdge; p; p = p->Next) {
            if(Earliest[p->Index] < Earliest[vertexIndex] + p->Weight) {
                Earliest[p->Index] = Earliest[vertexIndex] + p->Weight;
            }
            if(--InDegree[p->Index] == 0) {
                Enqueue(&q, p->Index);
            }
        }
    }
    if(Vcount != graph->VertexNums) {
        printf("Impossible");
    }
    else {
        int max = 0;
        for(int i = 0; i < graph->VertexNums; i++) {
            if(Earliest[i] > max) {
                max = Earliest[i];
            }
        }
        printf("%d", max);
    }
}
int main() {
    int vertexNums, edgeNums;
    scanf("%d %d", &vertexNums, &edgeNums);
    ListGraph graph = BuildGraph(vertexNums, edgeNums);
    TopSort(graph);
    system("pause");
    return 0;
}                                                                                                                   


http://lihuaxi.xjx100.cn/news/1469320.html

相关文章

基于java医院门诊管理系统设计与实现

摘 要 在当今的中国新经济体制下&#xff0c;我国的经济水平发展迅速。并且随着我国经济的快速发展&#xff0c;信息化也得到了充分的发展。在这个信息的的潮流之下&#xff0c;随着计算机性能的不断的提高&#xff0c;计算机从之前的一个只有政府或是科研事业才能触及到的信息…

三维模型OSGB格式轻量化的纹理压缩和质量保持分析

三维模型OSGB格式轻量化的纹理压缩和质量保持分析 在三维模型应用中&#xff0c;纹理数据是一个重要的部分&#xff0c;可以为模型增加更多的真实感和细节。但是&#xff0c;由于纹理数据通常会占用大量的存储空间和传输带宽&#xff0c;因此&#xff0c;在OSGB格式轻量化处理中…

限制 el-input 输入 emoji

1. 电脑如何输入 emoji 表情 ? 快捷键 win; 或 win. 2. 代码实现 <template><el-input v-model"input" placeholder"请输入内容" input"inputChange"></el-input> </template><script> export default {name: D…

ABBYY FindReader2024免费版电脑PDF格式扫描软件

在日常工作和生活中&#xff0c;我们有时需要将各种格式的文件转换为PDF格式&#xff0c;也可能需要将纸质文件扫描成PDF文档。今天要和大家分享的是PDF扫描软件哪个好&#xff0c;如何把多个扫描件合成一个PDF。 PDF作为目前主流的文件格式之一&#xff0c;在日常生活中我们需…

面试题 16.11. 跳水板

​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;面试题 16.11. 跳水板 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 使用哈希表记录所有可能结果&#xff0c;然后再将哈希表中的数据放入数组中&#xff0c;最后对数组进行排序即可。 解题…

Matlab论文插图绘制模板第108期—特征渲染的标签散点图

在之前的文章中&#xff0c;分享了Matlab标签散点图的绘制模板&#xff1a; 进一步&#xff0c;再来分享一下特征渲染的标签散点图的绘制模板&#xff0c;以便再添加一个维度的信息。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中…

字节跳动推出免费域名DNS和公共DNS服务

近日&#xff0c;字节跳动旗下云计算服务火山引擎推出了 TrafficRoute DNS 套件&#xff0c;套件提供了从公网到私网、从递归到权威的全链路 DNS 服务以及基于 DNS 的流量调度服务&#xff0c;包含了云解析&#xff08;DNS&#xff09;、云调度&#xff08;GTM&#xff09;、私…

手写 Mybatis-plus 基础架构(工厂模式+ Jdk 动态代理统一生成代理 Mapper)

这里写目录标题 前言温馨提示手把手带你解析 MapperScan 源码手把手带你解析 MapperScan 源码细节剖析工厂模式Jdk 代理手撕脚手架&#xff0c;复刻 BeanDefinitionRegistryPostProcessor手撕 FactoryBean代理 Mapper 在 Spring 源码中的生成流程手撕 MapperProxyFactory手撕增…