嘿,我一直在开发这种用于研究的“项目管理工具”,它应该计算任务持续时间和成本,以确定任何给定项目的关键路径,例如:
en example of a project and tasks relations
我实现了一个Task Class,如下所示:
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:我没有包含getter和setter
我还有一个名为project的类,如下所示:
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:对不起长代码:)
答案 0 :(得分:0)
找到从一个源节点到另一个源节点的最长路径是一般形式的NP难问题,因此没有多项式解决方案。 与此相反,使用Dijkstra或Bellman-Ford算法可以轻松找到最短路径。 我不是专家,但我真的建议重新考虑你能做什么以及你在练习中不能做什么。