题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
题意:
5 2 //5个进程(编号从 0 开始)需要被执行,有2个约束条件, 问全部执行完成的最短时间。
1 2 1 //1号要在2号进程执行完成的后一纳秒执行
3 4 1
Sample Output
2
关键路径:
基于AOE网(Activity On Edge),也就是说,每一条边代表着一个事件的发生,边的权值即为事件的花费时间。
节点可以抽象理解为一个状态。在拓扑序列中,后面的状态是由前面的状态经过事件的发生(边)到达的,从 0 节点(什么都没做)到 n - 1 (完成 n 个事件)的状态。
关键路径是由关键节点组成的路径,关键路径上所需时间为完成这个工程(n 个事件)最少花费时间。
可以用来解决的问题:eg,有一项工程,工程有 n 个事件,有些可以同步发生,而有些有先后执行的顺序限制, 问完成工程的最少时间?
关键节点:
要想在最短时间完成工程,那么关键节点的最早发生时间和最晚发生时间是相同的。这需要正反两次拓扑排序。
思路:
这道题只需要正向拓扑排序,求出关键路径上所需时间即可。
对于输入:
5 3
0 1 3
1 2 4 //可以理解为从 2 号状态(已经完成了事件 2 和事件 0 的状态)花费间隔 3 纳秒,可以到达 1 状态。
3 4 3
#include <stdio.h> #include <queue> #include <math.h> #include <string.h> #include <algorithm> using namespace std; const int N = 1007; typedef struct Edge { int w; int to; int next; }edge; edge eg[N * 10]; int n, m, head[N], isVis[N], in[N], out[N], val[N]; //val记录每个状态的时间,记录到达当前状态最长的时间 queue <int> q; int criticalPath() { int max = -1; while (!q.empty()) q.pop(); memset(val, 0, sizeof(val)); for (int i = 0; i < n; i++) { if (!in[i]) { val[i] = 1; q.push(i); isVis[i] = 1; } } while (!q.empty()) { int temp = q.front(); q.pop(); if (val[temp] > max) max = val[temp]; int r = head[temp]; while (r != -1) { in[eg[r].to]--; if (val[eg[r].to] < val[temp] + eg[r].w - 1) val[eg[r].to] = val[temp] + eg[r].w - 1; if (!in[eg[r].to] && !isVis[eg[r].to]) { val[eg[r].to]++; isVis[eg[r].to] = 1; q.push(eg[r].to); } r = eg[r].next; } } return max; } int main() { while (scanf("%d%d", &n, &m) != EOF) { memset(isVis, 0, sizeof(isVis)); memset(head, -1, sizeof(head)); for (int i = 1; i <= m; i++) { int u, v, w; scanf("%d%d%d", &v, &u, &w); eg[i].to = v; eg[i].w = w; in[v]++; out[u]++; eg[i].next = head[u]; head[u] = i; } printf("%d\n", criticalPath()); } return 0; }
时间: 2024-10-29 00:11:20