动态规划算法

这篇博客深入探讨了动态规划算法在不同问题中的应用,包括最大值连续子序列、找零问题、最长递增子序列等经典问题,以及平衡分区、箱子堆叠、建造桥梁等挑战性问题。每个问题都提供了解决方案,并分析了时间复杂度。
摘要由CSDN通过智能技术生成

问题来源以及讲解
https://people.cs.clemson.edu/~bcdean/dp_practice

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[k1]+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[kv[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[i1][j],P[i1][jAi]},且当 j − A i = = 0 j-A_i==0 jAi==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] 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值