• DP:凑零钱问题/最长非降子序列(C++)


    你给出一定数额的钱 i 元给我,我利用手中的硬币(m元, j元, k元...)兑换等值的钱给你,要求硬币数最少。

    举例:给出1-11的钱,手中硬币有1元,3元,5元。

    重点是找到状态和状态转移方程。

    具体可以看这里:点击进入

    引用自上面链接:

     最终我们要求解的问题,可以用这个状态来表示:d(11),即凑够11元最少需要多少个硬币。 那状态转移方程是什么呢?既然我们用d(i)表示状态,那么状态转移方程自然包含d(i), 上文中包含状态d(i)的方程是:d(3)=min{d(3-1)+1, d(3-3)+1}。没错, 它就是状态转移方程,描述状态之间是如何转移的。当然,我们要对它抽象一下,

    d(i)=min{ d(i-vj)+1 },其中i-vj >=0,vj表示第j个硬币的面值;

    因此可以列出函数式:

    const vector<int> Func(vector<int> &coin){
        vector<int> MIN(12);
        for(int i = 1; i <= 11; ++i){//从1~11元,寻找每次最少兑换硬币数
            MIN[i] = 99;//这里我理解为初始的状态值,赋值为不可能取值
            for(int j = 0; j < coin.size(); ++j){
                if(coin[j] <= i && MIN[i-coin[j]] + 1 < MIN[i])
                    MIN[i] = MIN[i - coin[j]] + 1;
                }
            }
            return MIN;
    }
    coin[i] <= i表示,我给的硬币不能超过你给我的钱大小,不然亏了。

    最长非降子序列的长度

    先看看引言:

    如果我们要求的这N个数的序列是:

    5,3,4,8,6,7
    

    根据上面找到的状态,我们可以得到:(下文的最长非降子序列都用LIS表示)

    • 前1个数的LIS长度d(1)=1(序列:5)
    • 前2个数的LIS长度d(2)=1(序列:3;3前面没有比3小的)
    • 前3个数的LIS长度d(3)=2(序列:3,4;4前面有个比它小的3,所以d(3)=d(2)+1)
    • 前4个数的LIS长度d(4)=3(序列:3,4,8;8前面比它小的有3个数,所以 d(4)=max{d(1),d(2),d(3)}+1=3)

    OK,分析到这,我觉得状态转移方程已经很明显了,如果我们已经求出了d(1)到d(i-1), 那么d(i)可以用下面的状态转移方程得到:

    d(i) = max{1, d(j)+1},其中j<i,A[j]<=A[i]
    

    用大白话解释就是,想要求d(i),就把i前面的各个子序列中, 最后一个数不大于A[i]的序列长度加1,然后取出最大的长度即为d(i)。 当然了,有可能i前面的各个子序列中最后一个数都大于A[i],那么d(i)=1, 即它自身成为一个长度为1的子序列。

    代码:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int func(vector<int> &vec) {
        vector<int> MAX(vec.size());
        int len = 1;
        for (int i = 0; i < vec.size(); ++i) {
            MAX[i] = 1;
            for (int j = 0; j < i; ++j)
                if (vec[j] <= vec[i] && MAX[j] + 1 > MAX[i])
                    MAX[i] = MAX[j] + 1;
            if (MAX[i] > len)
                len = MAX[i];
        }
        return len;
    }
    int main() {
        vector<int> vec = { 5, 3, 4, 8, 6, 7};
        cout << func(vec) << endl;
    
        system("PAUSE");
        return 0;
    }

    如果这道题我们改一下,要求最长连续非降序序列长度,又该是怎样呢?

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int func(vector<int> &vec) {
        vector<int> MAX(vec.size());
        int len = 1, i = 0, j = 0;
        for (; i < vec.size(); ++i) {
            MAX[i] = 1;
            for (; j < i; ++j)
                if (vec[j] <= vec[i] && MAX[j] + 1 > MAX[i])
                    MAX[i] = MAX[j] + 1;
            if (MAX[i] > len)
                len = MAX[i];
        }
        return len;
    }
    int main() {
        vector<int> vec = { 5, 3, 4, 8, 6, 7};
        cout << func(vec) << endl;
    
        system("PAUSE");
        return 0;
    }
  • 相关阅读:
    CRC在线计算器
    freemodbus-v1.5.0 源码分析
    图及其实现
    最短路径
    交换排序-------快速排序
    FreeRTOS--删除任务
    Install OE and BitBake
    高端编程之DOM
    timeout使用实例
    使用JS提交表单
  • 原文地址:https://www.cnblogs.com/Mayfly-nymph/p/10567746.html
Copyright © 2020-2023  润新知