简体   繁体   中英

How can i Analyse and Discover all possible paths in an activity network

Hey , i have been developing this kind of a "project management tool" for study it is supposed to calculate tasks durations and cost to determine a critical path for any given project like this for example :

en example of a project and tasks relations

**until now i calculated all the durations and starts and finishes but i'm stuck with how to discover all the possible paths in such a graph and how to traverse this structure from the initial node to the final node and determine witch path will take the longest duration and i have no idea how to continue so thanks in advance for helping me **

I implemented a Task Class as follow :

public class Task {

    private String name;
    private int duration;
    private int earlyStart;
    private int earlyFinish;
    private int lateStart;
    private int lateFinish;
    private int totalFloat;
    private HashSet<Task> predecessors;
    private HashSet<Task> successors;
    private String[] dependencies;

    public Task(String taskName, int taskDuration, String[] dependencies) {
        // Initialize Attributes
        this.name = taskName;
        this.duration = taskDuration;
        this.dependencies = dependencies;
        this.predecessors = new HashSet<Task>();
        this.successors = new HashSet<Task>();
    }
}

Ps : i didn't include the getters and setters

and i have also a class called project implemented as follow :

public class Project {

private HashSet<Task> tasks;
private HashSet<Task> initialTasks;
private HashSet<Task> finalTasks;
private int maxDuration;

public Project() {
    this.tasks = new HashSet<Task>();
}

public void initialize(){

    this.calculateTasksRelation();
    this.calculateInitialTasks();
    this.calculateInitialTasksEarlies();
    this.forwardPass();

    this.calculateFinalTasks();
    this.calculateMaxDuration();
    this.calculateFinalTasksLates();
    this.backwardPass();

}




public void addTask(Task task) {
    this.tasks.add(task);
}

public Task getTaskByName(String taskName) {
    for (Task task : tasks) {
        if(task.getName().equals(taskName)){
            return task;
        }
    }
    return null;
}

public HashSet<Task> getAllTasks() {
    return tasks;
}

/**
 * Private Methods internal Usage Only
 * */
private void calculateTasksRelation() {
    for (Task current : tasks) {
        if ( current.getDependencies() != null ) {
            for (String string : current.getDependencies() ) {
                if (this.getTaskByName(string) != null) {
                    Task dependencie = this.getTaskByName(string);
                    current.addPredecessor(dependencie);
                    dependencie.addSuccessor(current);
                }
            }
        }
    }
}

// Return only the tasks that dosn't have predecessors
private void calculateInitialTasks(){
    HashSet<Task> remaining = new HashSet<Task>(this.tasks);
    // itertare over the remaining and remove all tasks 
    // that are successors = they have predecessor
    for (Task current : tasks) {
        for (Task successor : current.getSuccessors()) {
            remaining.remove(successor);
        }
    }
    this.initialTasks = new HashSet<>(remaining);
}

private void calculateInitialTasksEarlies() {
    for (Task initialTask : this.initialTasks) {
        initialTask.setEarlyStart(0);
        initialTask.setEarlyFinish(initialTask.getEarlyStart() + initialTask.getDuration());
    }
}

private void calculateMaxDuration() {

    for (Task task : finalTasks) {
        if(task.getEarlyFinish() > this.maxDuration) {
            this.maxDuration = task.getEarlyFinish();
        }
    }
}

// Return only the tasks that dosn't have any successors
private void calculateFinalTasks() {
    HashSet<Task> remaining = new HashSet<Task>(this.tasks);
    // itertare over the remaining and remove all tasks 
    // that are predecessors = they have successor
    for (Task current : tasks) {
        for (Task predecessor : current.getPredecessors()) {
            remaining.remove(predecessor);
        }
    }
    this.finalTasks = new HashSet<>(remaining);
}

private void calculateFinalTasksLates() {
    for (Task endTask : this.finalTasks) {
        endTask.setLateFinish(this.maxDuration);
        endTask.setLateStart(endTask.getLateFinish() - this.maxDuration);
    }
}

private void forwardPass() {
    // tasks whose early starts has been calculated
    HashSet<Task> completed = new HashSet<Task>(initialTasks);
    // tasks whose early starts has not been calculated yet
    HashSet<Task> remaining = new HashSet<Task>(tasks);
    remaining.removeAll(initialTasks);

    // Backflow algorithm
    // while there are tasks whose early start isn't calculated.
    while (!remaining.isEmpty()) {
        boolean progress = false;
        for (Task currentTask : this.tasks) {
            if(completed.containsAll(currentTask.getPredecessors())){
                int temp = 0 ;
                for ( Task dependencie : currentTask.getPredecessors() ) {
                    if( dependencie.getEarlyFinish() > temp ){
                        // update the temp variable
                        temp = dependencie.getEarlyFinish();
                    }
                }
                currentTask.setEarlyStart(temp);
                currentTask.setEarlyFinish(currentTask.getEarlyStart() + currentTask.getDuration());
                // set the task as completed and remove it from the remaining
                completed.add(currentTask);
                remaining.remove(currentTask);
                // note that we are making a progress
                progress = true;
            }
        }
        // If we haven't made any progress then a cycle must exist in
        // the graph and we wont be able to calculate the critical path
        if (!progress)
            throw new RuntimeException("Cyclic dependency, algorithm stopped!");
    }
}

private void backwardPass() {
    // tasks whose early starts has been calculated
    HashSet<Task> completed = new HashSet<Task>(this.finalTasks);
    // tasks whose early starts has not been calculated yet
    HashSet<Task> remaining = new HashSet<Task>(tasks);
    remaining.removeAll(finalTasks);

    // Backflow algorithm
    // while there are tasks whose early start isn't calculated.
    while (!remaining.isEmpty()) {
        boolean progress = false;
        for (Task currentTask : this.tasks) {
            if(completed.containsAll(currentTask.getSuccessors())){
                int temp = this.maxDuration;
                for ( Task successor : currentTask.getSuccessors() ) {
                    if( successor.getLateStart() < temp ){
                        // update the temp variable
                        temp = successor.getLateStart();
                    }
                }
                currentTask.setLateFinish(temp);
                currentTask.setLateStart(currentTask.getLateFinish() - currentTask.getDuration());
                // set the task as completed and remove it from the remaining
                completed.add(currentTask);
                remaining.remove(currentTask);
                // note that we are making a progress
                progress = true;
            }
        }
        // If we haven't made any progress then a cycle must exist in
        // the graph and we wont be able to calculate the critical path
        if (!progress)
            throw new RuntimeException("Cyclic dependency, algorithm stopped!");
    }
}
}

Ps : Sorry for the long code :)

Finding the longest path from one source node to another one is an NP-hard problem in the general form, so there is no polynomial solution to it. Contrary to it, finding the shortest path is kind of easy to solve using Dijkstra's or Bellman-Ford's algorithm. I am not an expert, but I would really suggest to reconsider what you can and what you cannot do in the exercise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM