动态规划

题目来源于up主正月点灯笼 https://www.bilibili.com/video/av16544031

ex1

 图中每一个矩形代表一个任务,每个任务都得在某个时间段内完成,同一时间段只能完成一个任务。完成每个任务后可以得到奖励,求最大的奖励。

prev[i]为最接近i的那个可以完成的任务,与起始时间最接近的

第i个任务的最优解=第i个任务不选的情况下第七个任务的最优解与选了第八个任务加上第prev[i]个任务的最优解

opt[i] = Math.max(opt[i - 1], money[i] + opt[prev[i]]);
public class ex1 {
    public static void main(String[] args) {
        //表示每个任务的时间段
        int[][] nums = {{0, 0},{1, 4}, {3, 5}, {0, 6}, {4, 7}, {3, 8}, {5, 9}, {6, 10}, {8, 11}};
        int[] money = {0, 5, 1, 8, 4, 6, 3, 2, 4};
        int[] opt = new int[nums.length];
        int[] prev = new int[nums.length];

        for(int i = 1;i < nums.length;i++){
            for(int j = i - 1;j >= 0;j--){
                if(nums[j][1] <= nums[i][0]){
                    prev[i] = j;
                    break;
                }
            }
        }
        System.out.println(Arrays.toString(prev));
        for(int i = 1;i < opt.length;i++){
            opt[i] = Math.max(opt[i - 1], money[i] + opt[prev[i]]);
        }
        System.out.println(Arrays.toString(opt));
        System.out.println(opt[opt.length - 1]);

    }
}

ex2

有一个整数数组,要求从数组中取出一系列数字,且数字不能是连续的,求使这些数字和为最大的序列。

opt[i] = Math.max(opt[i - 1], nums[i] + opt[i - 2]);

实现如下

public class ex2 {

    public static void main(String[] args) {
        int[] nums = {1, 2, 4, 1, 7, 8, 3};
        int[] opt = new int[nums.length];
        opt[0] = 1;
        opt[1] = 2;
        for(int i = 2;i < opt.length;i++){
            opt[i] = Math.max(opt[i - 1], nums[i] + opt[i - 2]);
        }
        System.out.println(opt[nums.length - 1]);
    }

}

ex3

对于上面的这个数组,要求选出一个序列,该序列的和为S。

这个问题也是一个动态规划问题,S为9,当前的i为5,有两个选择,可以选2使得S变成7,也可以不选2,在剩下的数组中继续挑选。

递归解法:

    public static void main(String[] args) {
        int[] arr = {3, 34, 4, 12, 5, 2};
        System.out.println(rec_subset(arr, 5, 13));
    }

    public static boolean rec_subset(int[] arr, int i, int s){
        if(s == 0){//如果当前的和已经为0
            return true;
        }else if (i == 0){//如果当前已经挑选到最后一个数
            return arr[0] == s;
        }else if(arr[i] > s){//如果当前值大于目标和
            return rec_subset(arr, i - 1, s);
        }else{
            return rec_subset(arr, i - 1,s)||rec_subset(arr, i - 1,s -arr[i]);
        }
    }

非递归解法 python:

import numpy as np

arr = [3, 34, 4, 12, 5, 2]


def dp_subset(arr, S):
    subset = np.zeros((len(arr), S + 1), dtype=bool)
    subset[:, 0] = True    # 已经挑选到最后一个数
    subset[0, :] = False   # 当前的和已经是0
    subset[0, arr[0]] = True
    for i in range(1, len(arr)):
        for s in range(1, S + 1):
            if arr[i] > s:
                subset[i, s] = subset[i - 1, s]
            else:
                subset[i, s] = subset[i - 1, s - arr[i]] or subset[i - 1, s]
    return subset[-1, -1]


print(dp_subset(arr, 13))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章