算法导论机考复习(动态规划)

动态规划求解方法

明确dp数组的含义; 明确小问题和大问题之间的关系; 初始化dp;确定遍历顺序;

//****动态规划****
//上楼梯问题,斐波那契数列问题,
//最简单的动态规划,直接自底向上逐步求解
#include<bits/stdc++.h>
using namespace std;
const int N=100000;
int n,dp[N];
int main()
{
    cin>>n;
    dp[0]=0;
    dp[1]=1;
    dp[2]=2;
    for(int i=3;i<=n;i++)
    {
        //dp[i]=dp[i-1]+1+dp[i-2]+1;
          dp[i]=dp[i-1]+dp[i-2];
    }
    cout<<dp[n];
}

求最大连续子数组问题

//****动态规划****
//最大连续序列问题
//注意并不是最后最大,而是中间就可能出现最大的连续子序列
#include<bits/stdc++.h>
using namespace std;
const int N=100000;
int n,dp[N],a[N],maxx;
int main()
{
    cin>>n;
    for(int i=1;i<n;i++)
    {
        cin>>a[i];
    }
    dp[0]=0;
    for(int i=1;i<=n;i++)
    {
        dp[i]=max(dp[i-1]+a[i],a[i]);
        maxx=max(dp[i],maxx);
    }
    cout<<maxx;
}

求最大连续子矩阵问题的时候,通过计算一个前缀值,把一个二维的问题转化为限定上下界的一维问题

//****动态规划****
//求一个二维矩阵的最大子矩阵问题
//二维问题通过中间的计算转化为一维问题
//以后用动态规划求解数组还是矩阵问题的时候输入都从1开始
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int n,dp[N],qian[N][N],maxx,a[N][N];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>a[i][j];
            qian[i][j]=qian[i-1][j]+a[i][j];
            //前缀是这一位置到顶部的前缀和
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)
            //这外面这两层循环确定了上界以及下界
        {
            for(int k=1;k<=n;k++)//这一层相当于求一个
            {
                dp[k]=max(dp[k-1]+qian[j][k]-qian[i-1][k],qian[j][k]-qian[i-1][k]);
                maxx=max(maxx,dp[k]);
            }
        }
    }

    cout<<maxx<<endl;
}

求序列值的和  : 求最大上升子序列问题,dp的含义就是以i结尾的序列的最长上升子序列长度;

初始化是每个dp的值最初都对应a值,对于第一个它的最长上升子序列就是a[1]

遍历策略是从1遍历到n,测试前面所有的上升序列的情况,大于就更新。然后更新maxx

求序列的长度  :dp的意思不同了只是,代码差不多

//****动态规划****
//求最大不连续上升子序列问题
//要求不连续就不想前面那么简单了,
//需要找出前面的所有可能的情况然后比较找出最大的
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int a[N],dp[N];
int maxx,n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    dp[0]=0;
    for(int i=1;i<=n;i++)
    {
        dp[i]=a[i];//a[i]后面进行更新,没有更新则就是a[i]
        for(int j=1;j<i;j++)
        {
            if(a[i]>a[j])
            {
                dp[i]=max(dp[i],dp[j]+a[i]);
            }
        }
        maxx=max(maxx,dp[i]);
    }
  cout<<maxx;
}

LCS求最长公共子序列问题,根据动态规划的画表法;

dp数组初始化ij所有有0的dp值都是0;

遍历策略是两层循环所有的s,只要遍历到的两个字符相等就******

如果不等就******

每次得出dp之后更新maxx

//****动态规划****
//求两个字符串的最长公共子序列问题
//第一次用二维的dp的数组
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int n,maxx,m;
string s1,s2;
int dp[N][N];
//dp[i][j] s1的前i个和s2的前j个,一共有几个公共序列
int main()
{
    cin>>s1;
    cin>>s2;
    n=s1.length();
    m=s2.length();
    
    for(int i=1;i<=n;i++)//ij从1开始是为了dp好写
    //访问s的时候还是用i-1
    {
        for(int j=1;j<=m;j++)
        {
            if(s1[i-1]==s2[j-1])
                //dp物理意义下的字符串的位置是否相等
            {
                dp[i][j]=dp[i-1][j-1]+1;
            }
            else
            {
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
            maxx=max(maxx,dp[i][j]);
        }
    }
    cout<<maxx;
}


经典的0-1背包问题, dp[i][j]表示当放第i个物品而且包里面容量为j的时候的最大价值

根据画表的顺序,两层循环,放不进去就直接等于放上一个物品时候的状态,可以放进去比较不放

dp[i-1][j] 和放dp[i-1][j-w]+v的大小,最后输出dp[n][bao]

//****动态规划****
//求两个字符串的最长公共子序列问题
//第一次用二维的dp的数组
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int bao,n;
int w[N],v[N],dp[N][N];
int main()
{
    cin>>n>>bao;
    for(int i=1;i<=n;i++)
    {
      cin>>w[i]>>v[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=bao;j++)
        {
            if(w[i]<j)
            {
                dp[i][j]=dp[i-1][j];
            }
            else
            {
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
            }
        }
    }
    cout<<dp[n][bao];
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值