動態規劃

題目來源於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))

 

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