动态规划:线性DP

这篇具有很好参考价值的文章主要介绍了动态规划:线性DP。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 数字三角形:

#include<iostream>
using namespace std;

const int N=510,INF=0x3f3f3f3f;
int f[N][N];//存路径长度
int a[N][N];//存数字

int main()
{
    int n;
    scanf("%d",&n);

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }

    //为何j从0开始,i+1结束:因为下面的max算的时候,三角形最左的位置(j=1)没有左上角,需要j=0的值
    for(int i=1;i<=n;i++)
    {                        
        for(int j=0;j<=i+1;j++)//三角形最右的位置(j=i)没有右上角,需要i+1的位置
        {
            f[i][j]=-INF;//所有值初始化为负无穷
        }
    }

    f[1][1]=a[1][1];//走到第一个点的长度为a[1][1]
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {   //走到ij的长度加前一个点的长度
            f[i][j]=a[i][j]+max(f[i-1][j-1],f[i-1][j]);//判断左上和右上哪个更大,题目要求最大路径
        }
    }

    int res=-INF;
    for(int i=1;i<=n;i++) res=max(res,f[n][i]);//寻找存的最大路径长度
    printf("%d\n",res);
}

最长上升子序列 I:

#include <iostream>

using namespace std;

const int N = 1010;

int n;
int a[N];//存数字
int f[N];//存路径长度

int main() 
{
    scanf("%d",&n);
    for (int i = 0; i < n; i++) scanf("%d",&a[i]);

    for (int i = 0; i < n; i++) //以i号数字结尾
    {
        f[i] = 1;    // 设f[i]默认为1,找不到前面数字小于自己的时候就为1
        for (int j = 0; j < i; j++)
        {
            if (a[i] > a[j]) 
            {
                f[i] = max(f[i], f[j] + 1);//前一个小于自己的数结尾的最大上升子序列加上自己,即+1
                //这里为何用max而不直接用fj+1,题目没说连续序列,比如:1 3 9 8,8可以由1+3+8也可以9+8,而后判断的9+8是比1+3+8小的
            }
        }
    }
    
    int k=1;
    for(int i=0;i<n;i++)//找最长路径
    {
        if(f[k]<f[i])
        k=i;
    }   
    
    printf("%d\n",f[k]);//输出最长长度
    
    return 0;
}

最长上升子序列 II:

#include<iostream>
#include<algorithm>
using namespace std;

const int N=1e5+10;
int arr[N];

int main() 
{
    int n; 
    scanf("%d",&n);

    for (int i = 0; i < n; ++i)scanf("%d",&arr[i]);

    vector<int>stk;//模拟堆栈
    stk.push_back(arr[0]);

    for (int i = 1; i < n; i++) 
    {
        if (arr[i] > stk.back())//如果该元素大于栈顶元素,将该元素入栈
            stk.push_back(arr[i]);
        else//替换掉第一个大于或者等于这个数字的那个数
            *lower_bound(stk.begin(), stk.end(), arr[i]) = arr[i];
    }
    printf("%d\n",stk.size());
    return 0;
}
/*
例 n: 7
arr : 3 1 2 1 8 5 6

stk : 3

1 比 3 小
stk : 1

2 比 1 大
stk : 1 2

1 比 2 小
stk : 1 2

8 比 2 大
stk : 1 2 8

5 比 8 小
stk : 1 2 5

6 比 5 大
stk : 1 2 5 6

stk 的长度就是最长递增子序列的长度
*/

最长公共子序列;

#include <iostream>
using namespace std;

const int N = 1010;
int n, m;
char a[N], b[N];//a是第一个字符串,b是第二个字符串
int f[N][N];//f存的是状态,即长度

int main()
{
    scanf("%d%d",&n,&m);//a和b的长度
    cin>>a+1>>b+1;//从下标1开始存字符串
  
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (a[i] == b[j]) //如果ai和bj相同,赋予[i-1,j-1]+1的长度
            {
                f[i][j] = f[i - 1][j - 1] + 1;
            } 
            else //如果不相同,比较[i-1,j]和[i,j-1]的长度并赋给ij。
            {    //其实就是让上一个相同字符串的长度赋给现在,因为是i在外j在内,所以一直是用i,j-1来赋给ij,但是当j==m时,j又回到1,此时的上一个状态就不是i,j-1了,而是i-1,j
                f[i][j] = max(f[i - 1][j], f[i][j - 1]);
            }
        }
    }
    printf("%d\n",f[n][m]);
    return 0;
}

最短编辑距离:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int m, n;
char a[N],b[N];//两个字符串
int dp[N][N];//所有把a中的前i个字母 变成 b中前j个字母的集合的操作次数。前面是a,后面是b

int main()
{
    scanf("%d%s", &m,a+1);
    scanf("%d%s", &n,b+1);

    //预处理
    for(int i = 0; i <= m; i++) dp[i][0] = i;  //全删除,b的第0个比较a的第i个,则说明删除i次了
    for(int i = 0; i <= n; i++) dp[0][i] = i;  //全插入,a的第0个比较b的第i个,则说明插入i次了

    for(int i = 1; i <=m; i++)
        for(int j = 1; j <=n; j++)
        {
            dp[i][j] = min(dp[i-1][j],dp[i][j-1])+1;//先进行删除操作和添加操作
            if(a[i]==b[j]) dp[i][j] = min(dp[i][j],dp[i-1][j-1]);//若该字符相等,则次数与上次相等
            else dp[i][j] = min(dp[i][j],dp[i-1][j-1]+1);//若该字符不相等,则判断添加删除操作后的操作数与上一字符的操作数+1比较大小
        }

    printf("%d\n",dp[m][n]);

    return 0;
}

编辑距离:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 1e1 + 5, M = 1e3 + 10;

int n, m;
char str[M][N];//字符串数组,前面是字符串个数,后面是字符串
int dp[N][N];

int edit_distance(char a[], char b[])
{
    int la = strlen(a + 1), lb = strlen(b + 1);//从1号位置计算字符串长度
     //预处理,因为后面用得到0号位,所以从0开始
    for(int i = 0; i <= la; i++) dp[i][0] = i;  //全删除,b的第0个比较a的第i个,则说明删除i次了
    for(int i = 0; i <= lb; i++) dp[0][i] = i;  //全插入,a的第0个比较b的第i个,则说明插入i次了

    for(int i = 1; i <=la; i++)
        for(int j = 1; j <=lb; j++)
        {
            dp[i][j] = min(dp[i-1][j],dp[i][j-1])+1;//删除操作和添加操作
            if(a[i]==b[j]) dp[i][j] = min(dp[i][j],dp[i-1][j-1]);//若该字符相等,则判断+1
            else dp[i][j] = min(dp[i][j],dp[i-1][j-1]+1);//若该字符不相等,则判断添加删除操作后的操作数与上一字符的操作数+1比较大小
        }
        
    return dp[la][lb];//因为从0开始的,所以lalb就是最后一个
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++) cin>>str[i]+1;//输入n个字符串

    while (m--) 
    {
        int res = 0;
        char s[N];//给定字符串
        int limit;//限制步骤数
        cin >> (s + 1) >> limit;
        for (int i = 1; i <= n; i++) 
        {
            if (edit_distance(str[i], s) <= limit)//判断该字符串是否可以变成给定字符串
            {
                res++;
            }
        }
        printf("%d\n",res);
    }

    return 0;
}

文章来源地址https://www.toymoban.com/news/detail-736298.html

到了这里,关于动态规划:线性DP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AcWing算法学习笔记:动态规划(背包 + 线性dp + 区间dp + 计数dp + 状态压缩dp + 树形dp + 记忆化搜索)

    算法 复杂度 时间复杂度0(nm) 空间复杂度0(nv) 代码 算法 通过滚动数组对01背包朴素版进行空间上的优化 f[i] 与 f[i - 1]轮流交替 若体积从小到大进行遍历,当更新f[i, j]时,f[i - 1, j - vi] 已经在更新f[i, j - vi]时被更新了 因此体积需要从大到小进行遍历,当更新f[i, j]时,f[i - 1,

    2024年02月21日
    浏览(43)
  • acwing算法基础之动态规划--DP习题课1

    暂无。。。 暂无。。。 题目1 :最长严格上升子序列,要求时间复杂度为 O ( n l o g n ) O(nlogn) O ( n l o g n ) 。 解题思路:保存每个长度下的最小的结尾元素值,遍历数组元素时,通过二分找到它,然后更新它即可,返回len。 该算法的关键步骤如下: 定义向量 vec , vec[i] 表示

    2024年02月03日
    浏览(52)
  • 算法竞赛备赛之动态规划训练提升,DP基础掌握

    01背包问题是在M件物品中选择若干件放在空间为W的背包中,每件物品的体积为W1,W2至Wn,价值为P1,P2至Pn,01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。 01背包问题常常采用动态规划的方法去求解,状态转移方程为:F(W,i)=max{F(W,

    2024年02月08日
    浏览(43)
  • acwing算法基础之动态规划--数位统计DP、状态压缩DP、树形DP和记忆化搜索

    暂无。。。 暂无。。。 题目1 :求a~b中数字0、数字1、…、数字9出现的次数。 思路:先计算1~a中每位数字出现的次数,然后计算1~b-1中每位数字出现的次数,两个相减即是最终答案。 那么,如何计算1~a中每位数字出现的次数呢? 首先,将a的每一位存入向量num中,例如a=123

    2024年02月04日
    浏览(51)
  • 算法基础复盘笔记Day11【动态规划】—— 区间DP、计数类DP、树形DP、记忆化搜索

    ❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于 Java后端开发 ,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得 关注 、 点赞 、 收藏 、 评论 ⭐️⭐️⭐️ 📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉 1. 题目

    2024年02月01日
    浏览(42)
  • 动态规划(DP)入门——线性DP

    在了解线性DP之前,我们首先要知道什么是动态规划,即为将一种复杂问题,分解成很多重叠的子问题,并通过子问题的解得到整个问题的解的算法。听起来比较抽象,动态规划简单来说就是确定问题的状态,通常题目都会提示,一般为“到第i个为止,xx为j(xx为k)的方案数/最

    2024年02月19日
    浏览(48)
  • 动态规划——线性DP

    暴力搜索:由可行的所有起点出发,搜索出所有的路径。 但是深搜的算法时间复杂度要达到 O ( 2 n ) O(2^n) O ( 2 n ) (每个数都有选或不选的两个选择),指数级的时间复杂度在本题中( n ≤ 100 n≤100 n ≤ 100 )显然是不能接受的。那么再观察这个这棵递归树,可以发现其中有很

    2024年01月19日
    浏览(48)
  • 动态规划:线性DP

    2024年02月06日
    浏览(40)
  • [动态规划]——线性DP(LIS/LCS/LCIS等) 详解

    线性DP,是较常见的一类动态规划问题,其是在线性结构上进行状态转移,这类问题不像背包问题、区间DP等有固定的模板 线性动态规划的目标函数为特定变量的线性函数,约束是这些变量的线性不等式或等式,目的是求目标函数的最大值或最小值 因此,除了少量问题(如:

    2024年02月10日
    浏览(45)
  • DP算法:动态规划算法

    (1)确定初始状态 (2)确定转移矩阵,得到每个阶段的状态,由上一阶段推到出来 (3)确定边界条件。 蓝桥杯——印章(python实现) 使用dp记录状态,dp[i][j]表示买i张印章,凑齐j种印章的概率 i表示买的印章数,j表示凑齐的印章种数 情况一:如果ij,不可能凑齐印章,概

    2024年02月07日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包