任务调度计划(动态规划DP)

公司的服务器上,每天会有大量的任务在队列中等待调度每个任务a执行需要消耗一定的资源量resource[a]调度的过程中有下列要求:

  1. 每一天可以同时并行调度多项任务,但是每天最少需要调度一项任务,每个任务的完成时间是一天
  2. 第k天调度a任务的前提:保证b任务在k-1天调度完成或者在第k天和a任务同时被调度(0<=b<a)

现在公司需要制定一个调度计划,使得在给定的天数(n)内完成所有任务的调度,并且使得总的资源消耗量最小。调度的总消耗指的是n天每一天的消耗之和,而一天的调度消耗指的是当天所有调度任务中资源量消耗最大的任务。如果n天内无法完成所有任务的调度,则输出-1

输入描述

两行输入

第1行:2个整数,调度计划的总天数n,总任务数m
第2行:一行字符串,表示各项任务调度所需要的资源量,各个任务的资源量按照空格分割

数据范围:

1≤n≤1000,1≤m≤1000

输出描述

最优调度的总消耗

示例

输入输出示例仅供调试,后台判题数据一般不包含示例
输入
3 8
7 2 5 10 8 1 2 4
输出
15

翻译一下:

给定一个非负整数数组 nums 和一个整数 m ,将这个数组分成 m 个非空的连续子数组。
求这 m 个子数组各自最大值之和的最小值。

思路

这是一个经典的动态规划问题,可以使用动态规划来解决。下面是解决该问题的步骤:

  1. 首先,确定动态规划的状态。我们可以定义一个二维数组 dp,其中 dp[i][j] 表示将数组的 [0,i] 的元素分成 (j +1)个子数组时最小的子数组最大值之和。
  2. 初始化边界条件。当只有一个子数组时,每个子数组的最大值就是数组中的最大值。因此,我们可以将 dp[i][0] 初始化为数组[0,i] 的元素的最大值。
  3. 接下来,我们需要计算 dp[i][j] 的值。我们可以使用一个额外的变量存储数组区间的最大值,然后从 0 开始遍历到i-1(变量k),将数组分成两部分。在计算 dp[i][j] 时,我们可以将数组的(k,i] 的元素作为一个子数组,将剩余的元素分成 j-1 个子数组。这样,dp[i][j] 的值就可以通过 dp[k][j-1] 和区间(k,i]的最大值来计算。
  4. dp[taskNum - 1][dayNum - 1] 即为所求的结果。

题解如下:

import java.util.Scanner;

public class Solution {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int dayNum = scanner.nextInt();
        int taskNum = scanner.nextInt();
        int[] resources = new int[taskNum];
        for (int i = 0; i < taskNum; i++) {
            resources[i] = scanner.nextInt();
        }
        int solution = new Solution().solution(dayNum, taskNum, resources);
        System.out.println(solution);

    }

    int solution(int dayNum, int taskNum, int[] resources) {
        if (dayNum > taskNum) {
            return -1;
        }
        // dp[i][j]表示[0,i]的任务被分配到j天
        int[][] dp = new int[taskNum][dayNum];
        for (int i = 0; i < taskNum; i++) {
            for (int j = 0; j < dayNum; j++) {
                dp[i][j] = Integer.MAX_VALUE/2;
            }
        }
        // maxV[i][j]表示区间[i,j]中的最大值
        int[][] maxV = new int[taskNum][taskNum];
        for (int i = 0; i < taskNum; i++) {
            for (int j = i; j < taskNum; j++) {
                if (i == 0 && j == 0)
                    maxV[i][j] = resources[0];
                else
                    maxV[i][j] = Math.max(resources[j], maxV[i][j - 1]);
            }
        }
        for (int i = 0; i < taskNum; i++) {
            // 将[0,i]划分为(j+1)部分
            for (int j = 0; j < i + 1 && j < dayNum; j++) {
                if (j == 0) {
                    dp[i][j] = maxV[0][i];
                    continue;
                }
                for (int k = j - 1; k < i; k++) {
                    dp[i][j] = Math.min(dp[i][j], dp[k][j - 1] + maxV[k + 1][i]);
                }
            }
        }
        return dp[taskNum - 1][dayNum - 1];
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值