问题来源以及讲解
https://people.cs.clemson.edu/~bcdean/dp_practice
Dynamic Programming
文章目录
- Dynamic Programming
Maximum Value Contiguous Subsequence.
Given a sequence of n real numbers A [ 1 ] A[1] A[1]… A [ N ] A[N] A[N], determine a contiguous subsequence A [ i ] A[i] A[i]… A [ j ] A[j] A[j] for which the sum of elements in the subsequence ∑ k = i j A [ k ] \sum_{k=i}^jA[k] ∑k=ijA[k] is maximized.
Solution
We first set an array M [ N ] M[N] M[N] to store the maximum sum of elements in the subsequence,and M [ k ] M[k] M[k] is the maximum sum of the subsequence which ends at A [ k ] A[k] A[k]. Then we get M [ k ] = max ( M [ k − 1 ] + A [ k ] , A [ k ] ) M[k]=\max (M[k-1]+A[k], A[k]) M[k]=max(M[k−1]+A[k],A[k])time efficient is O ( n ) O(n) O(n)
def Max_Sum_Seq(A):
dp = A
for i in range(1, len(A)):
dp[i] = max(dp[i-1]+A[i], A[i])
return max(dp)
vector<int> Max_Sum_Seq(vector<int>& A){
vector<int> dp(A.begin(), A.end());
for(int i = 1; i < A.size(); i++)
dp[i] = max(dp[i-1]+A[i], A[i]);
return dp;
}
Making Change.
You are given n n n types of coin denominations of values v [ 1 ] < v [ 2 ] < . . . < v [ N ] v[1] < v[2] < ... < v[N] v[1]<v[2]<...<v[N] (all integers). Assume v [ 1 ] = 1 v[1] = 1 v[1]=1, so you can always make change for any amount of money C C C. Give an algorithm which makes change for an amount of money C C C with as few coins as possible.
Solution
We set an array of M [ C ] M[C] M[C], M [ k ] M[k] M[k] means the minimum number of coins to make change for k k k. M [ k ] = min i M [ k − v [ i ] ] + 1 M[k]=\min_i{M[k-v[i]]}+1 M[k]=iminM[k−v[i]]+1time efficient is O ( N C ) O(NC) O(NC)
def Make_Change(A, C):
dp = [C] * (C+1)
dp[0] = 0
for i in range(1, C+1):
for v in A:
if i - v < 0:
break
dp[i] = min(dp[i-v]+1, dp[i])
return dp[C]
int Make_Change(vector<int>& A, int C){
vector<int> dp(C, C+1);
dp[0] = 0;
for(int i = 1; i < C+1; i++){
for(int j = 0; j < A.size(); j++){
if(i-A[j] < 0) break;
dp[i] = min(dp[i-A[j]]+1, dp[i]);
}
}
return dp[C];
}
Longest Increasing Subsequence.
Given a sequence of n n n real numbers A [ 1 ] . . . A [ n ] A[1] ... A[n] A[1]...A[n], determine a subsequence (not necessarily contiguous) of maximum length in which the values in the subsequence form a strictly increasing sequence.
O ( n 2 ) O(n^2) O(n2) Solution
We set an array of M [ N ] M[N] M[N], in which M [ k ] M[k] M[k] stores the maximum length ending at A [ k ] A[k] A[k]. M [ k ] = max A [ i ] < A [ k ] ( M [ i ] + 1 ) M[k]=\max_{A[i]<A[k]}(M[i]+1) M[k]=A[i]<A[k]max(M[i]+1) time efficient is O ( n 2 ) O(n^2) O(n2)
def LIS(A):
dp = [1] * (len(A)+1)
dp[0] = 0
for i in range(1, len(A)+1):
for k in range(i):
if A[k] < A[i]:
dp[i] = max(dp[k]+1, dp[i])
return max(dp)
vector<int> LIS(vector<int>& A){
vector<int> dp(1, A.size()+1);
dp[0] = 0;
for(int i = 1; i < A.size()+1; i++){
for(int k = 0; k < i; k++){
if(A[k] < A[i])
dp[i] = max(dp[k]+1, dp[i]);
}
}
return dp;
}
O ( n log ( n ) ) O(n\log(n)) O(nlog(n)) Solution
We reserve an array e n d s ends ends to store the longest and maximum numbers in the increasing array;
int LIS(vector<int>& A){
vector<int> ends({
A[0]});
for(int i = 1; i < A.size(); i++){
if(A[i] < ends[0]) ends[0] = A[i];
else if(A[i] > ends.back()) ends.emplace(A[i]);
else{
int left = 0, right = ends.size();
while(left < right){
int mid = (left + right)/2;
if(A[i] > ends[mid]) left = mid;
else right = mid;
}
ends[right] = A[i];
}
}
return ends.size();
}
所有子列的可能的和
有一个非负数列 A = { A 1 , . . . , A n } A=\{A_1, ..., A_n\} A={ A1,...,An}, 计算所有的可能子列的和
Solution
所有子列和的最大值为 m a = ∑ i n A i ma=\sum_i^n{A_i} ma=∑inAi, 最小值为 m i = min { A } mi=\min\{A\} mi=min{ A}. 矩阵 P [ n ] [ m ] P[n][m] P[n][m]存储可能的和. 其中 P [ i ] [ j ] = 1 P[i][j]=1 P[i][j]=1表示前 i i i个元素 { A 1 , . . . , A i } \{A_1, ..., A_i\} { A1,...,Ai}中存在和为 j j j的子列, 否则 P [ i ] [ j ] = 0 P[i][j]=0 P[i][j]=0,则 P [ i ] [ j ] = max { P [ i − 1 ] [ j ] , P [ i − 1 ] [ j − A i ] } P[i][j]=\max\{P[i-1][j], P[i-1][j-A_i]\} P[i][j]=max{ P[i−1][j],P[i−1][j−Ai]},且当 j − A i = = 0 j-A_i==0 j−Ai==0时, P [ i ] [ j ] = 1 P[i][j]=1 P[i][j]=1。时间空间复杂度均为 O ( n m ) O(nm) O(nm)
def Possible_Sum(A: list):
import numpy as np
P = np.zeros((len(A), sum(A)+1))
for i in range(len(A)):
for j in range(sum(A)+1):
if i > 0 and j-A[i]>=0:
P[i][j]