题目大意:给你 n 个任务,编号从 1 ~ n , 有些任务有前驱任务 ,即前驱任务完成后才能开始该任务,当然,相互之间没有影响的任务可以同时进行,完成每个任务都需要一定的时间,问:完成所有任务需要的最少时间是多少?
解题思路:这个题有点像拓扑排序,因为要开始每个任务前都要完成某些任务,即任务的完成是有先后顺序的,具体方法就是:将每个任务看成一个点,将入度为 0 的点压入队列,然后遍历队列中的顶点(设为 k)的邻接顶点(设为 m ),即 k 是 m 的前驱顶点,更新开始任务 m 所需要的最晚时间 ,同时顶点 m 的入度 减 1 ,当顶点 m 入度为 0 时,把m 压入队列,重复以上步骤,直到队列为空。
请看代码:
#include <iostream>
#include <set>
#include <algorithm>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <stack>
#include <cstring>
#include <map>
#include <vector>
#include <string>
#include <queue>
#include <cmath>
#define eps 1e-7
#define mem(a , b) memset(a , b , sizeof(a) )
using namespace std ;
const int MAXN = 11111 ;
struct Edge
{
int adj ;
int d ;
int next ;
} e[MAXN * 200] ;
int t[MAXN] ; // 存储完成每个任务所需要的时间
int dis[MAXN] ; // 存储开始每个任务的最晚时间
int ind[MAXN] ; // 统计每个顶点的入度
int head[MAXN] ;
int n ;
int ecnt ;
void chu()
{
mem(t , 0) ;
mem(dis , 0) ;
mem(head , -1) ;
mem(ind , 0) ;
mem(vis , 0) ;
ecnt = -1 ;
}
void init()
{
int i ;
for(i = 1 ; i <= n ; i ++)
{
scanf("%d" , &t[i]) ;
int tt ;
scanf("%d" , &tt) ;
ind[i] = tt ;
int j ;
for(j = 0 ; j < tt ; j ++)
{
int a ;
scanf("%d" , &a) ;
ecnt ++ ;
e[ecnt].adj = i ;
e[ecnt].d = t[a] ;
e[ecnt].next = head[a] ;
head[a] = ecnt ;
}
}
}
queue<int> q ;
void spfa()
{
while (!q.empty()) q.pop() ;
int i ;
for(i = 1 ; i <= n ; i ++)
{
if(ind[i] == 0)
q.push(i) ;
}
int tu ;
while(!q.empty())
{
tu = q.front() ;
q.pop() ;
int i ;
for(i = head[tu] ; i != -1 ; i = e[i].next)
{
int td = e[i].d ;
int v = e[i].adj ;
ind[v] -- ;
if(ind[v] == 0) // 当入度为0的时候,就把该点压入队列
{
q.push(v) ;
}
if(dis[tu] + td > dis[v])
{
dis[v] = dis[tu] + td ;
}
}
}
}
void solve()
{
spfa() ;
int i ;
int MAX = 0 ;
for(i = 1 ; i <= n ; i ++)
{
MAX = max(MAX , dis[i] + t[i]) ;
}
printf("%d\n" , MAX) ;
}
int main()
{
while(scanf("%d" , &n) != EOF)
{
chu() ;
init() ;
solve() ;
}
return 0 ;
}