计算复杂职业管理日期的算法

时间:2018-05-16 11:55:28

标签: algorithm date

你好伙伴Stack Overflowers,

我有一种情况,我需要一些帮助来选择使算法工作的最佳方法,目标是管理资源的占用(让资源A考虑)具有多个任务,以及每个任务需要的位置完成指定的时间。在第一阶段,我不想涉及多个变量,所以让我们保持简单的方式,让我们考虑他只有工作日的时间表。

例如:

1 - 我们有1个资源,资源A

2 - 资源A的工作时间为星期一至星期五上午8点至下午4点,为了保持简单,他现在没有午餐,所以每天工作8小时。

3 - 资源A有5个任务要完成,为了避免这个级别的复杂性,让我们每个人花费10个小时才能完成。

4 - 资源A将于2018-05-16正好在下午2点开始完成这项任务。

问题: 现在,我需要知道的是所有5个任务的正确完成日期,但考虑到所有先前的限制。

在这种情况下,他有6个工作日,另外还有第7天的2个小时。 我想要的预期结果是:2018-05-24(下午4点)。

实施 我想了两个选项,并希望对这些选项或其他我可能不会考虑的选项有反馈。

算法1

1 - 创建一个“插槽”列表,其中每个“插槽”代表1小时,持续x天。

2 - 使用资源的小时计划交叉此插槽列表,以删除资源不在此处的所有插槽。这将返回一个列表,其中包含他可以实际工作的插槽。

3 - 用我为他完成的任务占用剩余的插槽。

4 - Finnaly,检查最后一个占用位置的日期/小时。

缺点:我认为这可能是一个矫枉过正的解决方案,考虑到我不想考虑他未来的职业,我想要知道什么时候完成任务。< / p>

算法2

1 - 将任务小时(50小时)添加到开始日期,获取expectedFinishDate。 (将获得预期的完成日期= 2018-05-18(下午4点))

2 - 将开始日期和expectedFinishDate之间的小时数与计划相交,以获得他将无法工作的小时数。 (基本上会得到不可用的小时数,一天16小时,会导致剩余的小时数= 32小时)。

3 - 使用不可用的小时数计算新的expectedFinishDate,将这个32小时添加到之前的2018-05-18(下午4点)。

4 - 用新的expectedFinishDate重复第2点和第3点,直到remainingHoursForCalc = 0.

缺点:这会导致递归方法或非常奇怪的while循环,再次,我认为这对于计算简单日期可能是过度的。

你会建议什么?有没有其他选择,我可能不会考虑,这会使这更简单?或者您认为有一种方法可以改进这2种算法中的任何一种以使其有效吗?

2 个答案:

答案 0 :(得分:1)

我同意算法1是过度的。

我想我会确保我的条件是正确的:每天工作时间(8),工作日(周一,周二,周三,周四,周五)。然后将所需的小时数(5 * 10 = 50)除以每天的小时数,因此我知道需要多少工作日(50/8 = 6)。稍高一点,先按小时每周除以(50/40 = 1周)。计算从开始日期开始的工作日,以获得结束日期的第一次拍摄。该部门可能还有剩余部分,因此请使用此选项确定任务是在当天结束还是在下一个工作日结束。

答案 1 :(得分:1)

改进版本:

import java.util.Calendar;
import java.util.Date;

public class Main {

public static void main(String args[]) throws Exception
{

    Date d=new Date();
    System.out.println(d);
    d.setMinutes(0);
    d.setSeconds(0);
    d.setHours(13);


    Calendar c=Calendar.getInstance();
    c.setTime(d);
    c.set(Calendar.YEAR, 2018);
    c.set(Calendar.MONTH, Calendar.MAY);
    c.set(Calendar.DAY_OF_MONTH, 17);

    //c.add(Calendar.HOUR, -24-5);
    d=c.getTime();
    //int workHours=11;
    int hoursArray[] = {1,2,3,4,5, 10,11,12, 19,20, 40};
    for(int workHours : hoursArray)
    {
        try
        {
            Date end=getEndOfTask(d, workHours);
            System.out.println("a task starting at "+d+" and lasting "+workHours
                + " hours will end at " +end);
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }

}

public static Date getEndOfTask(Date startOfTask, int workingHours) throws Exception
{
    int totalHours=0;//including non-working hours
    //startOfTask +totalHours =endOfTask
    int startHour=startOfTask.getHours();
    if(startHour<8 || startHour>16)
        throw new Exception("a task cannot start outside the working hours interval");
    System.out.println("startHour="+startHour);
    int startDayOfWeek=startOfTask.getDay();//start date's day of week; Wednesday=3
    System.out.println("startDayOfWeek="+startDayOfWeek);
    if(startDayOfWeek==6 || startDayOfWeek==0)
        throw new Exception("a task cannot start on Saturdays on Sundays");
    int remainingHoursUntilDayEnd=16-startHour;
    System.out.println("remainingHoursUntilDayEnd="+remainingHoursUntilDayEnd);
    /*some discussion here: if task starts at 12:30, we have 3h30min 
     * until the end of the program; however, getHours() will return 12, which
     * substracted from 16 will give 4h. It will work fine if task starts at 12:00,
     * or, generally, at the begining of the hour; let's assume a task will start at HH:00*/
    int remainingDaysUntilWeekEnd=5-startDayOfWeek;
    System.out.println("remainingDaysUntilWeekEnd="+remainingDaysUntilWeekEnd);
    int completeWorkDays = (workingHours-remainingHoursUntilDayEnd)/8;
    System.out.println("completeWorkDays="+completeWorkDays);
    //excluding both the start day, and the end day, if they are not fully occupied by the task
    int workingHoursLastDay=(workingHours-remainingHoursUntilDayEnd)%8;
    System.out.println("workingHoursLastDay="+workingHoursLastDay);
    /* workingHours=remainingHoursUntilDayEnd+(8*completeWorkDays)+workingHoursLastDay */

    int numberOfWeekends=(int)Math.ceil( (completeWorkDays-remainingDaysUntilWeekEnd)/5.0 );
    if((completeWorkDays-remainingDaysUntilWeekEnd)%5==0)
    {
        if(workingHoursLastDay>0)
        {
            numberOfWeekends++;
        }
    }
    System.out.println("numberOfWeekends="+numberOfWeekends);

    totalHours+=(int)Math.min(remainingHoursUntilDayEnd, workingHours);//covers the case
    //when task lasts 1 or 2 hours, and we have maybe 4h until end of day; that's why i use Math.min

    if(completeWorkDays>0 || workingHoursLastDay>0)
    {
        totalHours+=8;//the hours of the current day between 16:00 and 24:00
        //it might be the case that completeWorkDays is 0, yet the task spans up to tommorrow
        //so we still have to add these 8h
    }
    if(completeWorkDays>0)//redundant if, because 24*0=0
    {           
        totalHours+=24*completeWorkDays;//for every 8 working h, we have a total of 24 h that have 
        //to be added to the date   
    }

    if(workingHoursLastDay>0)
    {
        totalHours+=8;//the hours between 00.00 AM and 8 AM
        totalHours+=workingHoursLastDay;
    }

    if(numberOfWeekends>0)
    {
        totalHours+=48*numberOfWeekends;//every weekend between start and end dates means two days
    }

    System.out.println("totalHours="+totalHours);

    Calendar calendar=Calendar.getInstance();
    calendar.setTime(startOfTask);
    calendar.add(Calendar.HOUR, totalHours);
    return calendar.getTime();
}
}

您可以调整hoursArray []或d.setHours以及c.set(Calendar.DAY_OF_MONTH,以测试各种开始日期以及各种任务长度。

由于在16:00到24:00之间增加了8小时,因此仍然存在错误: 从5月17日星期四13:00:00开始的任务2018年,持续11小时将于5月19日星期六00:00:00 EEST 2018结束

我保留了很多印刷语句,它们对调试非常有用。

这是术语解释: enter image description here