首页 > 其他分享 >chapter12-动态规划

chapter12-动态规划

时间:2024-03-17 13:33:59浏览次数:16  
标签:arr int maximum 序列 MAXN chapter12 answer 动态 规划

动态规划:就是用于求解优化问题的方法。优化问题比如说求最大值or最小值。动态规划的做法就是采用小心地策略进行暴力搜索,在多项式时间内求得最优解。

这里的小心策略就是复用子问题的解,将已解决子问题的答案保存下来,在需要子问题答案的时候便可以直接获得,而不需要重复计算,提高效率。拆分出来的子问题可以用递归的方式求解,而要复用子问题的解就要记忆化。

1.递推求解

接下来通过Fibonacci数列的求解来体会动态规划是如何降低时间复杂度的,从朴素的递归,到递归+记忆化(自顶向下求解),再到递推求解(自底向上求解)。

递归+记忆化
//Fibonacci数列求解的3种方式 2024-03-16
#include <iostream>
#include <cstdio>

using namespace std;
const int MAXN = 100;

//朴素递归求解,时间复杂度O(2^n),因为递归树的每个结点都要计算
int Fibonacci(int n) {
    int answer;
    if(n == 0 || n == 1) {
        answer = n;
    } else {
        answer = Fibonacci(n - 1) + Fibonacci(n - 2);
    }
    return answer;
}

//朴素递归+记忆化,时间复杂度O(n)
int memo[MAXN];
int Fibonacci2(int n) {
    if(memo[n] != -1) {
        return memo[n];
    }
    int answer;
    if(n == 0 || n == 1) {
        answer = n;
    } else {
        answer = Fibonacci2(n - 1) + Fibonacci2(n - 2);
    }
    memo[n] = answer;
    return answer;
}

//递推求解,时间复杂度O(n),和记忆化的本质和原理上是一模一样的
int fibo[MAXN];
int Fibonacci3(int n) {
    for(int i = 0; i <= n; ++i) {
        if(i == 0 || i == 1) {
            fibo[i] = i;
        } else {
            fibo[i] = fibo[i - 1] + fibo[i - 2];
        }
    }
    return fibo[n];
}


int main() {
    int n;
    fill(memo, memo + MAXN, -1);
    while(cin >> n) {
        // cout << Fibonacci(n) << endl;
        cout << Fibonacci2(n) << endl;
    }
    return 0;
}

动态规划的策略非常简单,就是将原始的问题拆分成多个子问题,并将子问题的结果记录下来,以方便我们之后复用这些子问题的解。

2.最大连续子序列和

动态规划最经典的问题之一。这个问题讨论的是,在一个给定的序列\(\{A1,A2,...,An\}\)中,找出一个连续的子序列\(\{Ai,...,Aj\}\),使得这个连续的子序列的和最大,输出这个最大的序列和。

最大连续子序列的和.jpg
这个问题难处理就在于左右两个端点都不定,所以我们首先假定右边端点A[j]是定的,在此基础上考虑把A[j]作为末尾的最大连续子序列和为可能为多少。

最大序列和
//最大连续子序列和 2024-03-17
#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
const int MAXN = 1e6 + 10;
const int INF = INT_MAX;

long long arr[MAXN];

//朴素递归+记忆化,O(n)
long long dp[MAXN];
long long MaxComponent(int n) {
    if(dp[n] != -1) {
        return dp[n];
    }
    long long answer;
    if(n == 0) {
        answer = arr[n];
    } else {
        answer = max(MaxComponent(n - 1) + arr[n], arr[n]);
    }
    dp[n] = answer;
    return answer;
}

//递推求解
long long dp2[MAXN];
void MaxComSum(int n) {
    for(int i = 0; i < n; ++i) {
        int answer;
        if(0 == i) {
            answer = arr[i];
        } else {
            answer = max(dp2[i - 1] + arr[i], arr[i]);
        }
        dp2[i] = answer;
    }
    return;
}

int main() {
    int n;
    while(cin >> n) {
        fill(dp, dp + MAXN, -1);
        for(int i = 0; i < n; ++i) {
            cin >> arr[i];
        }
        
        long long maximum = -INF;
        for(int i = 0; i < n; ++i) {
            maximum = max(maximum, MaxComponent(i));
        }
        cout << maximum << endl;
    }
    return 0;
}

3.最长递增子序列

动态规划最经典的问题之一。该问题描述的是在一个已知序列\(\{A_1,A_2,...,A_n\}\)中,取出若干元素(不必连续)组成一个新的序列\(\{A_x,...,A_y\}\),新序列中的各个数之间依旧保持原序列的先后顺序。若这个子序列中的任意下标\(x < y\)有\(A_x < A_y\),则称该子序列为原序列的一个递增子序列。最长递增子序列问题就是求给定序列的所有递增子序列中最长的那个子序列长度

最长递增子序列.jpg
同样是固定右边的一个端点,往前推这个子序列可以有几个元素。

最长上升子序列
//最长递增子序列 2024-03-17
#include <iostream>
#include <cstdio>

using namespace std;

const int MAXN = 1000 + 10;
const int INF = INT_MAX;
int arr[MAXN];

//朴素递归
int Fun1(int n) {
    int answer;
    if(n == 0) { //A[0]前面没有其他值,作为递归出口
        answer = 1;
    } else {
        answer = 1;
        for(int i = 0; i < n; ++i) {
            if(arr[i] < arr[n]) {
                answer = max(answer, Fun1(i) + 1);
            }
        }
    }
    return answer;
}

//朴素递归+记忆化,O(n^2)
int memo[MAXN];
int Fun2(int n) {
    if(memo[n] != -1) {
        return memo[n];
    }
    int answer;
    if(n == 0) {
        answer = 1;
    } else {
        answer = 1;
        for(int i = 0; i < n; ++i) {
            if(arr[i] < arr[n]) {
                answer = max(answer, Fun2(i) + 1);
            }
        }
    }
    memo[n] = answer;
    return answer;
}

//递推求解
int dp[MAXN];
void Fun3(int n) {
    for(int j = 0; j < n; ++j) {
        int answer;
        if(j == 0) {
            answer = 1;
        } else {
            answer = 1;
            for(int i = 0; i < j; ++i) {
                if(arr[i] < arr[j]) {
                    answer = max(answer, dp[i] + 1);
                }
            }
        }
        dp[j] = answer;
    }
    return;
}

int main() {
    int n;
    while(cin >> n) {
        for(int i = 0; i < n; ++i) {
            cin >> arr[i];
        }

        //recursive
        // int maximum = 0;
        // for(int i = 0; i < n; ++i) {
        //     maximum = max(maximum, Fun1(i));
        // }
        // printf("%d\n", maximum);

        //recursive + memorize
        // fill(memo, memo + MAXN, -1);
        // int maximum = 0;
        // for(int i = 0; i < n; ++i) {
        //     maximum = max(maximum, Fun2(i));
        // }

        //递推
        fill(dp, dp + MAXN, -1);
        Fun3(n);
        int maximum = 0;
        for(int i = 0; i < n; ++i) {
            maximum = max(maximum, dp[i]);
        }
        printf("%d\n", maximum);
    }
    return 0;
}

最长公共子序列先留个坑,以后用到再说咯,也和上面的做法差不多,要固定一侧端点,分析有几种情况 ,递归出口是什么。

标签:arr,int,maximum,序列,MAXN,chapter12,answer,动态,规划
From: https://www.cnblogs.com/paopaotangzu/p/18077323

相关文章

  • 动态路由匹配
    应用场景:通过动态路由参数的模式进行路由匹配<router-linkto="/user/1">User1</router-link><router-linkto="/user/2">User2</router-link><router-linkto="/user/3">User3</router-link><router-linkto="/us......
  • 【职业规划】人生职业规划的一些建议
    一、名言警句卡耐基说:“一个人的成功,15%靠专业知识。85%靠人际关系与处世能力。”。苏格拉底说:“没有经过思考的人生是不值得过的。”有反思才有更好的人生。莎士比亚说:“抛弃时间的人,时间也将抛弃他。”把时间用在达成目标的路上不懈怠,才会得到相应的收获。乔布斯说:“......
  • 动态规划·爬楼梯问题(一维)与印章问题(二维)
    算法介绍动态规划(DynamicProgramming)的核心是当前状态的解由上一状态得到。算法将求解问题分解成多个相似的子问题,每个子问题的解由上一个子问题的解得到并储存,往往用于优化递归问题,减少相同子问题的重复计算。一维动态规划·爬楼梯问题问题描述假设你正在爬楼梯,需要n ......
  • arp动态表缓存清除
    一、arp表里清除表状态:1,Delay:请求arp2,Reachab:响应arp3,Stale此状态下,待gc_stale_time超时后,准备gc_interval定期清理二、限制条件base_reachable_time:后变为Stalegc_thresh1:数量限制gc_stale_time:时间限制gc_interval:定期间隔三,测试在断开连接,经测试发现即使......
  • 专题 | 二分&0/1分数规划&数学期望
    二分二分编号对于一个有单调性的数组,我们可以二分编号,如果a[mid]<ans,那么mid就往a[]更大的那边走while(r>l){mid=(l+r)/2;if(judge(mid))l=mid;elser=mid;}注意二分代码的写法细节和你的check函数有关!(其实是和你在对于恰好满足要求时check返回值有......
  • 【无人机三维路径规划】基于磷虾群算法KH实现复杂地形下无人机避障三维航迹规划附Matl
     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......
  • 【机械臂路径规划】基于ADD-RRT、RRV、改进的Bridge Test等算法实现固定基座机械臂路
     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......
  • 【Python使用】python高级进阶知识md总结第4篇:静态Web服务器-命令行启动动态绑定端口
    python高级进阶全知识知识笔记总结完整教程(附代码资料)主要内容讲述:操作系统,虚拟机软件,Ubuntu操作系统,Linux内核及发行版,查看目录命令,切换目录命令,绝对路径和相对路径,创建、删除文件及目录命令,复制、移动文件及目录命令,终端命令格式的组成,查看命令帮助。HTTP请求报文,HTTP响应报文......
  • AntSK 0.2.1 版本揭秘:动态加载dll,驱动Function Call新境界!
        在.NET的无限宇宙中,动态加载dll似乎一直是操控代码生生不息的魔杖。今天,我将与您探讨如何通过AntSK0.2.1版本灵活运用dll,将FunctionCall的强大功能插拔自如地融入项目之中,我们走入插件化开发的全新篇章。新版本简介       AntSK,这个曾被我们广泛探讨过的......
  • Leetcode刷题-动态规划
    爬楼梯链接:70.爬楼梯-力扣(LeetCode)假设你正在爬楼梯。需要n阶你才能到达楼顶。每次你可以爬1或2个台阶。你有多少种不同的方法可以爬到楼顶呢?示例1:输入:n=2输出:2解释:有两种方法可以爬到楼顶。1.1阶+1阶2.2阶示例2:输入:n=3输出:3解释:有三种方法可......