题目来源于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))