蓝桥杯必备算法三:动态规划

算法原理

1.0 算法引入

动态规划相信大家都知道,动态规划算法也是新手在刚接触算法设计时很苦恼的问题,有时候觉得难以理解,但是真正理解之后,就会觉得动态规划其实并没有想象中那么难。网上也有很多关于讲解动态规划的文章,大多都是叙述概念,讲解原理,让人觉得晦涩难懂,即使一时间看懂了,发现当自己做题的时候又会觉得无所适从。我觉得,理解算法最重要的还是在于练习,只有通过自己练习,才可以更快地提升。动态规划方法求解的最优化问题应该具备的两个要素:最优子结构和子问题重叠。我们还会再次讨论备忘方法,更深入地讨论在自顶向下方法中如何借助备忘机制来充分利用子问题重叠特性。

2.0 什么问题能通过动态规划解决?

能采用动态规划求解的问题的一般要具有3个性质:

  1. 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
  2. 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
  3. 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)

3.0 解题步骤

我们解决动态规划问题一般分为四步:

  1. 定义一个状态,这是一个最优解的结构特征
  2. 进行状态递推,得到递推公式
  3. 进行初始化
  4. 返回结果

经典例题

老鹰吃小鸡

题目描述

在这里插入图片描述

在这里插入图片描述

题目思路及代码

思路: 背包问题

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+10;
ll n;
ll a[maxn],b[maxn];
ll dp[100010];
ll sum=0;
int main(){
    
    
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
    
    
        scanf("%lld",&b[i]);
    }
    for(int i=1;i<=n;i++){
    
    
        scanf("%lld",&a[i]);
    }
    ll ma=0;
    for(int i=1;i<=n;i++){
    
    
        for(ll j=n;j>=b[i];j--){
    
    
            dp[j]=max(dp[j],dp[j-b[i]]+a[i]);
            ma=max(ma,dp[j]);

        }

    }
    printf("%lld",ma);
	return 0;
}


删括号

链接:原题链接
来源:牛客网

题目描述

给你一个合法的括号序列s1,每次你可以删除一个"()"
你可以删除0个或者多个"()"
求能否删成另一个括号序列s2

输入描述:
第一行输入一个字符串s (2|s|100)
第二行输入一个字符串t (2|t|100 )
输出描述:
如果可以输出"Possible"
否则输出"Impossible"

输入输出请打开题目链接有!

题目思路及代码

思路: 用k=删除’(’-删除’)'的数,具体看代码
代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const ll N=105;
bool dp[N][N][N];
char str[N],str1[N];
int main()
{
    
    
 ios::sync_with_stdio(false);
 cin.tie(0);
 cout.tie(0);//对cin,cout的优化 
 cin>>str+1;
 cin>>str1+1;
 dp[0][0][0]=true;//边界初始化 
 for(int i=0;i<=strlen(str+1) ;i++)
 {
    
    
  for(int j=0;j<=strlen(str1+1) ;j++)
  {
    
    
   for(int k=0;k<=strlen(str+1)/2;k++)
   {
    
    
    if(dp[i][j][k])
    {
    
    
     if(!k&&str[i+1]==str1[j+1])dp[i+1][j+1][k]=true;//如果成立则前i+1中和j+1相匹配 
     if(str[i+1]=='(')dp[i+1][j][k+1]=true;//无论成立不,都要试试删除str[i+1] 
     else if(k)dp[i+1][j][k-1]=true; //如果有')',则有一对被删,k--; 
    }
   }
  }
 }
 if(dp[strlen(str+1)][strlen(str1+1)][0])cout<<"Possible"<<endl;//遍历到最后看看是否有成立的情况 
 else cout<<"Impossible"<<endl;
 return 0;
 }

其他题目请翻看动态规划专栏!!!

结语


“遇事不决可问春风,春风不语即随本心”的意思是:对一件事犹豫不决,就问春风该如何做,春风给不出答案,就凭自己本心做出决断。“遇事不决可问春风,春风不语即随本心”一句出自网络作家“烽火戏诸侯”的《剑来》,其原文是:“遇事不决,可问春风。春风不语,遵循己心”。

在这里插入图片描述


猜你喜欢

转载自blog.csdn.net/weixin_46627433/article/details/123647844