CC30A Algoritmos y estructuras de datos

Clase Auxiliar 03/11/2000

Construcción de cartas Pert

La representación del proyecto es la siguiente:

Existen actividades y dependencias:

  1. Las actividades son aristas y tienen asociado su tiempo
  2. Los nodos son estados en el proyecto.
Hay un estado "inicio" y uno "final" del proyecto.

Un estado se alcanza cuando se completan todas las tareas que llegan a el, y sólo ahí pueden empezar las tareas que salen de el.

Se desea saber cual es el minimo tiempo en que se puede completar el proyecto y cuales son las tareas críticas (las tareas que si se atrasan atrasan todo).

Veamos un ejemplo:

Los nodos A, B, C, D, E y F representan estados del proyecto, los nodos i y f, son nodos ficticios de modo de asegurar que el proyecto tiene un inicio único, y un fin único.

Los pasos necesarios para resolver el problema son:

  1. Calcular las dependencias.
  2. Marcar los tiempos mínimos de inicio.
  3. Calcular las precedencias.
  4. Marcar los tiempos máximos de inicio.
  5. Buscar los nodos con tiempo inicial mínimo igual al tiempo inicial máximo. Los arcos entre estos nodos son las tareas críticas.
Pert makePert (Grafo g) {
    Pert pert;
    asigna todas las dependencias y precedencias en 0;
    calcDep(pert, g, i);
    calcIniMin (pert, g);
    calcPre(pert, g, f);
    calcIniMax (pert, g);
    buscaCriticas(pert);
    return pert;
}

Estructura de datos necesaria para construir la carta Pert es:

Inicialmente la estructura indica 0 precedencias, 0 dependencias, tiempo mínimo 0, tiempo inicio máximo INFINITO
 
Nodo
i
A
B
C
D
E
F
f
Nº Dependencias (dep)
0
0
0
0
0
0
0
0
Nº Precedencias (pre)
0
0
0
0
0
0
0
0
tiempo inicio mínimo (min)
0
0
0
0
0
0
0
0
tiempo inicio máximo (max)
INFINITO
INFINITO
INFINITO
INFINITO
INFINITO
INFINITO
INFINITO
INFINITO

Cálculo de las dependencias

Para esto vamos a revisar el grafo hacia adelante:

Inicialmente las dependencias estan en 0.

void calcDep(Pert p, Grafo g, nodo i){
    if revisado(i) == FALSE {
        while haySig(g, i) {
            sig= sigNodo(g, i);
            p[sig].dep++;
            calcDep(p, g, sig);
        }
    }
    revisado(i) = TRUE;
}

Cálculo de los tiempos de inicio mínimo

void calcIniMin (Pert p){
    para cada nodo en Pert p
        p[min]= 0;

    while noCeroDep(p){
        i= sigCeroDep(p);
        p[i].dep--;
        while haySig(g, i) {
            s= sig(g, i);
            p[s].dep--;
            aux= costo(g, i, s) + p[i].min;
            if aux > p[s].min then
                p[s].min = aux;
        }
    }
}

Cálculo de las dependencias

Idem a calcDep, pero mirando hacia atras el grafo

Cálculo de los tiempos de inicio máximo

Idem a calcIniMin, pero todos parten con tiempo del nodo "f", y mirando hacia atras el grafo

Búsqueda de tareas críticas (sin holgura)

buscaCriticas(pert){
    Para cada nodo i en Pert p
        Si p[i].ini == p[i].max
            marcaCritico(i);

    Para todo par (i, j), con i y j nodos críticos
        revisar que el par (i, j) sea un arco válido, y que su costo sea igual a p[j].ini - p[i].ini
}