你好伙伴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种算法中的任何一种以使其有效吗?
答案 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结束。
我保留了很多印刷语句,它们对调试非常有用。