算法学习之动态规划(个人学习)

一、动态规划的思想:

将待求解问题分解为若干子问题,先求解这些子问题的解,再结合子问题的解得到原问题的解。

用一个表记录所有已解决的子问题的答案,不管该子问题以后是否被用到,只要它被计算过,就将结果填入表中。

二、与分治的区别:

适用于动态规划法求解的问题经分解得到的子问题往往不是相互独立的。若用分治法来解这类问题,则分解得到的子问题太多,以至于解决原问题需要耗费指数级时间。

三、求解步骤:

1、找出最优解的性质,并刻画其结构特征

2、递归地定义最优解

3、以自顶向上的方法计算最优值

4、根据计算最优值得到的信息,构造最优解

四、动态规划例题之矩阵连乘问题:

题目描述

  一个n*m矩阵由n行m列共n*m个数排列而成。两个矩阵A和B可以相乘当且仅当A的列数等于B的行数。一个N*M的矩阵乘以一个M*P的矩阵等于一个N*P的矩阵,运算量为nmp。
  矩阵乘法满足结合律,A*B*C可以表示成(A*B)*C或者是A*(B*C),两者的运算量却不同。例如当A=2*3 B=3*4 C=4*5时,(A*B)*C=64而A*(B*C)=90。显然第一种顺序节省运算量。
  现在给出N个矩阵,并输入N+1个数,第i个矩阵是a[i-1]*a[i]

输入

第一行n(n<=100)
第二行n+1个数

输出

  最优的运算量

样例输入 Copy
3
2 3 4 5
样例输出 Copy
64

分析题目:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 105;
typedef long long LL;
LL dp[N][N];
LL a[N];
LL solve(int l, int mid, int r)
{
    return (LL)a[l] * (LL)a[mid] * (LL)a[r];
}
void unRe(){
    int a = 1, b = 2, c = 3, d = 4;
    a = b + c * d;
    b = a ++ + c - d + c;
}
int main()
{
    int n;
    cin >> n;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            dp[i][j] = 1e18;
     
    for(int i=1; i<=n+1; i++)
    {
        cin >> a[i];
        dp[i][i] = 0;
    }
    for(int k=1; k<=n; k++)
        for(int i=k; i>=1; i--)
            for(int j=k-1; j>=i; j--)
                dp[i][k] = min(dp[i][k], dp[i][j]+dp[j+1][k]+a[i]*a[j+1]*a[k+1]);
    cout << dp[1][n] << endl;
    return 0;
}

五、最长公共子序列

若给定两个序列X,Y,当另一个序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。

例如,若X={A,B,C,B,D,A,B},Y={B,D,C,A,B,A} 则{B,C,A}是一个公共子序列,但不是最长的。

{B,C,B,A}是一个最长的公共子序列。这个不是连续的哦。

题目描述

       需要你做的就是写一个程序,得出最长公共子序列。
       最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。

输入

    第一行给出一个整数N(0<N<100)表示待测数据组数
    接下来每组数据两行,分别为待测的两组字符串。每个字符串长度不大于1000.

输出

   每组测试数据输出一个整数,表示最长公共子序列长度。每组结果占一行。

样例输入 Copy
2
asdf
adfsd
123abc
abc123abc
样例输出 Copy
3
6

分析题目:

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        string a,b;
        cin>>a>>b;
        int m=a.length();
        int n=b.length();
        int dp[m+1][n+1];
        //给边框加0
        //给第一行加0
        for(int i=0;i<m;i++)
        {
            dp[0][i]=0;
        }
        //给第一列加0
        for(int i=0;i<n;i++)
        {
            dp[i][0]=0;
        }
        //递归
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(a[i-1]==b[j-1])
                {
                    dp[i][j]=1+dp[i-1][j-1];
                }
                else
                {
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        printf("%d\n",dp[m][n]);
        
        
    }
    return 0;
}

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值