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