1.动态规划算法介绍
1.算法思路
动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。
2.代码介绍
// 推荐最优上机时间的方法,接收机器ID和上机类型ID作为参数
public static void recommendOptimalSessionTime(int machineID, int typeID) {
// 获取当前机器的会话列表,即所有已安排的上机时间段
List<Session> sessions = getSessionsByMachine(machineID);
// 计算最优时间槽,基于当前机器的会话列表、上机类型ID
List<TimeSlot> timeSlots = calculateOptimalTimeSlots(machineID, typeID, sessions);
// 如果存在可用的时间槽
if (!timeSlots.isEmpty()) {
// 获取效率最高的时间槽
TimeSlot optimalSlot = timeSlots.get(0);
// 打印推荐的最优上机时间详细信息
System.out.println("推荐的最优上机时间:");
System.out.println("开始时间:" + optimalSlot.getStartTime());
System.out.println("结束时间:" + optimalSlot.getEndTime());
System.out.println("效率:" + optimalSlot.getEfficiency());
} else {
// 如果没有可用的时间槽,则输出提示信息
System.out.println("没有可用的上机时间。");
}
}
// 交互式方法,提示用户输入机器ID和上机类型ID,并调用算法
private static void recommendOptimalSessionTime() {
// 用户输入机器ID
System.out.print("请输入机器ID:");
int machineID = scanner.nextInt();
scanner.nextLine();
// 用户输入上机类型ID
System.out.print("请输入上机类型ID:");
int typeID = scanner.nextInt();
scanner.nextLine();
// 调用算法执行推荐逻辑,并传入用户输入的机器ID和上机类型ID
recommendOptimalSessionTime(machineID, typeID);
}
// 核心算法方法,计算最优时间槽
public static List<TimeSlot> calculateOptimalTimeSlots(int machineID, int typeID, List<Session> sessions) {
List<TimeSlot> timeSlots = new ArrayList<>();
// 根据上机类型ID获取对应的费率,用于计算效率
double rate = getRateByTypeID(typeID);
// 初始化时间槽,从当前时间开始,每隔30分钟一个槽,持续24小时
long startTime = System.currentTimeMillis();
long endTime = startTime + 24 * 60 * 60 * 1000; // 结束时间为当前时间加24小时
long interval = 30 * 60 * 1000; // 时间槽间隔设置为30分钟
// 创建时间槽列表
for (long t = startTime; t < endTime; t += interval) {
// 每个时间槽从当前时间开始,持续30分钟
TimeSlot slot = new TimeSlot(new Timestamp(t), new Timestamp(t + interval));
timeSlots.add(slot);
}
// 动态规划计算每个时间槽的效率
for (TimeSlot slot : timeSlots) {
double efficiency = calculateEfficiency(slot, sessions, rate);
slot.setEfficiency(efficiency);
}
// 按效率从高到低排序时间槽
timeSlots.sort((a, b) -> Double.compare(b.getEfficiency(), a.getEfficiency()));
// 返回排序后的最优时间槽列表
return timeSlots;
}
// 计算单个时间槽的效率的方法
private static double calculateEfficiency(TimeSlot slot, List<Session> sessions, double rate) {
double efficiency = 0;
// 遍历所有会话,如果会话与时间槽冲突,则降低效率
for (Session session : sessions) {
if (slot.getStartTime().before(session.getEndTime()) && slot.getEndTime().after(session.getStartTime())) {
efficiency -= rate; // 效率降低,因为会话与时间槽冲突
}
}
// 如果时间槽内没有冲突的会话,则效率增加
efficiency += rate;
return efficiency;
}
3.算法应用概括
动态规划(Dynamic Programming, DP)是一种算法思想,它将复杂问题分解为更简单的子问题,通过解决子问题来构建解决方案。在给定的代码中,推荐最优上机时间的算法。
以下是使用动态规划思想的大致步骤:
在提供的代码中,我们有几个方法,每个方法都有特定的功能和参数列表。下面是对每个方法及其参数的分析:
1. `recommendOptimalSessionTime(int machineID, int typeID)`:
功能: 推荐基于机器ID和上机类型ID的最优上机时间。
参数:
`machineID`: 表示特定机器的唯一标识符。
`typeID`: 表示上机类型的唯一标识符。
2. `recommendOptimalSessionTime()`:
功能: 交互式方法,提示用户输入机器ID和上机类型ID,然后调用`recommendOptimalSessionTime(int, int)`方法。
参数: 无(直接使用`scanner`对象从用户那里获取输入)。
3. `calculateOptimalTimeSlots(int machineID, int typeID, List<Session> sessions)`:
功能: 计算给定机器和上机类型下的所有可能时间槽的最优时间槽列表。
参数:
`machineID`: 特定机器的ID。
`typeID`: 上机类型的ID。
`sessions`: 一个`Session`对象列表,表示当前机器上已经安排的会话。
4. `calculateEfficiency(TimeSlot slot, List<Session> sessions, double rate)`:
功能: 计算给定时间槽的效率,考虑了与现有会话的冲突和上机类型的费率。
参数:
`slot`: 要评估的`TimeSlot`对象。
`sessions`: 当前机器上已经安排的会话列表。
`rate`: 上机类型的费率,用于计算效率的影响。
5. `getRateByTypeID(int typeID)`:
功能: 根据提供的上机类型ID,从数据库中检索对应的费率。
参数:
`typeID`: 上机类型的ID。
6. `getSessionsByMachine(int machineID)`:
功能: 从数据库中检索与特定机器ID关联的所有会话。
参数:
`machineID`: 机器的ID。
方法内部逻辑分析:
`recommendOptimalSessionTime(int machineID, int typeID)`:
调用`getSessionsByMachine(machineID)`来获取特定机器的所有会话。
使用这些会话和上机类型ID调用`calculateOptimalTimeSlots(...)`来找到最优时间槽。
如果存在最优时间槽,打印其详细信息;否则,打印没有可用时间的信息。
`calculateOptimalTimeSlots(...)`:
初始化时间槽列表,从当前时间开始,每隔30分钟,直到24小时后。
对于每个时间槽,调用`calculateEfficiency(...)`来计算效率。
使用排序来找到效率最高的时间槽。
`calculateEfficiency(...)`:
对于每个时间槽,遍历所有会话,检查是否有冲突。
如果时间槽与会话时间重叠,降低效率值。
最终返回计算出的效率值。
`getRateByTypeID(typeID)` 和 `getSessionsByMachine(machineID)`:
这两个方法负责从数据库中检索必要的信息,它们使用预paredStatement来避免SQL注入,并处理数据库连接和结果集。