晴问算法 动态规划(简单)

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

动态规划的递归写法和递推写法

斐波那契数列II

题目描述

给定正整数�,求斐波那契数列的第�项�(�)。

令�(�)表示斐波那契数列的第�项,它的定义是:

当�=1时,�(�)=1;

当�=2时,�(�)=1;

当�>2时,�(�)=�(�−1)+�(�−2)。

输入描述

一个正整数�​(1≤�≤104​)。

输出描述

斐波那契数列的第�项�(�)。

由于结果可能很大,因此将结果对10007取模后输出。

#include <cstdio>
int fib[10001]={0};

int main() {
    int n;
    scanf("%d", &n);
    fib[1] = fib[2] = 1;
    for (int i = 3; i <= n; i++) {
        fib[i] = (fib[i - 1] + fib[i - 2])%10007;
    }
    printf("%d", fib[n]);
    return 0;
}

数塔II

题目描述

晴问算法 动态规划(简单),动态规划,算法,动态规划

数塔就是由一堆数字组成的塔状结构,其中第一行1个数,第二行2个数,第三行3个数,依此类推。每个数都与下一层的左下与右下两个数相连接。这样从塔顶到塔底就可以有很多条路径可以走,现在需要求路径上的数字之和的最大值。

例如在上图中,5->8->12->105->3->16->11这两条路径上的数字之和都是35,是所有路径中的最大值。

输入描述

第一行一个正整数�​(1≤�≤100​),表示数塔的层数。

接下来�​行为数塔从上到下的每一层,其中第�​层有�​个正整数,每个数都不超过1000

输出描述

从塔顶到塔底的所有路径中路径上数字之和的最大值。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    int a[102][102]={0};
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            cin>>a[i][j];
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=i;j>=1;j--){
            a[i][j]+=max(a[i+1][j],a[i+1][j+1]);
        }
    }
    cout<<a[1][1];
    return 0;
}

上楼II

题目描述

我打算走楼梯上楼,共有�级台阶。

我身轻如燕,所以每次都可以选择上一级台阶或者两级台阶。

问有多少种上楼的方式。

例如当�=3时,共有三种方式上楼:

  1. 一级 => 一级 => 一级;
  2. 一级 => 二级;
  3. 二级 => 一级。

输入描述

一个正整数�​(1≤�≤104​),表示台阶级数。

输出描述

一个整数,表示上楼的方案数。

由于结果可能很大,因此将结果对10007取模后输出。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin>>n;
    int a[100001];
    a[1]=1;
    a[2]=2;
    for (int i = 3; i <= n; i++) {
        a[i] = (a[i - 1] + a[i - 2])%10007;
    }  
    cout<<a[n];
    return 0; 
}

最大连续子序列和

最大连续子序列和

题目描述

现有一个整数序列�1,�2,...,��​​​,求连续子序列��+...+��​​​的最大值。

输入描述

第一行一个正整数�​​(1≤�≤104​​),表示序列长度;

第二行为用空格隔开的�​个整数��​(−105≤��≤105​​),表示序列元素。

输出描述

输出一个整数,表示最大连续子序列和。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    int a,b;
    int max1=-2222222;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a;
        if(i==1) b=a;
        else b=max(a,a+b);
        max1=max(max1,b);

    }
    cout<<max1;
    return 0;

}

最长不下降子序列(LIS)

最长上升子序列

题目描述

现有一个整数序列�1,�2,...,��​​​​​​,求最长的子序列(可以不连续),使得这个子序列中的元素是非递减的。输出该最大长度。

输入描述

第一行一个正整数�​​​​(1≤�≤100​​​​),表示序列长度;

第二行为用空格隔开的�​个整数��​(−105≤��≤105​​),表示序列元素。

输出描述

输出一个整数,表示最大长度。

#include<iostream>
using namespace std;
int main()
{
	int n;
	cin>>n;
	int a[1001]={0};
	int dp[1001]={0};
	int maxn=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		dp[i]=1;
		for(int j=1;j<i;j++){
			if(a[j]<=a[i]){
				dp[i]=max(dp[i],dp[j]+1);
				
			}

		}
		if(dp[i]>maxn) maxn=dp[i];
	}
	cout<<maxn;
	return 0;
} 

最长公共子序列(LCS)

最长公共子序列

题目描述

现有两个字符串�1​​​​与�2​,求�1​​​​与�2​​​​的最长公共子序列的长度(子序列可以不连续)。

输入描述

第一行为字符串�1​​,仅由小写字母组成,长度不超过100

第一行为字符串�2​​​,仅由小写字母组成,长度不超过100

输出描述

输出一个整数,表示最长公共子序列的长度。

#include<bits/stdc++.h>
using namespace std;
int main(){
    string a,b;
    cin>>a>>b;
    int dp[102][102]={0};
    for(int i=1;i<=a.length();i++){
        for (int j = 1; j <= b.length(); j++){
            if(a[i-1]==b[j-1]){
                dp[i][j]=dp[i-1][j-1]+1;
            }else{
                dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
            }
        }
    }
    cout<<dp[a.length()][b.length()];
    return 0;
}

最长回文子串

最长回文子串

题目描述

现有一个字符串�,求�的最长回文子串的长度。

输入描述

一个字符串�​​​​,仅由小写字母组成,长度不超过100

输出描述

输出一个整数,表示最长回文子串的长度。

//中点扩散算法
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int dp[N][N];
int main()
{
    string str;
    getline(cin,str);
    int res=0;
    for(int i=0;i<str.length();i++)
    {
        int l=i-1,r=i+1;//判断奇数长度回文串
        while(l>=0&&r<str.length()&&str[l]==str[r]) l--,r++;
        res=max(res,r-l-1);
        l=i,r=i+1;//判断偶数长度回文串
        while(l>=0&&r<str.length()&&str[l]==str[r]) l--,r++;
        res=max(res,r-l-1);
    }
    cout<<res<<endl;
    return 0;
}

背包问题

01背包问题

题目描述

有�件物品,每件物品的重量为��,价值为��。现在需要选出若干件物品放入一个容量为�的背包中(每件物品至多选一次),使得在选入背包的物品重量之和不超过容量�的前提下,让背包中物品的价值之和最大,求最大价值。

输入描述

第一行两个整数�​、�​(1≤�≤100,1≤�≤103​),分别表示物品数量、背包容量;

第二行为用空格隔开的�​个整数��​(1≤��≤10​),表示物品重量;

第三行为用空格隔开的�​个整数��​(1≤��≤10​),表示物品价值。

输出描述

输出一个整数,表示最大价值。

#include<bits/stdc++.h>
using namespace std ;
int ti[1005] , pri[1005] ;
int f[1005][1005] ;
int main()
{
	int t , m ;
	cin >> m>> t ;
    for(int i = 1 ; i <= m ; ++i){
        cin >> ti[i];
    }
    for(int i = 1 ; i <= m ; ++i){
        cin >> pri[i];
    }
	for(int i = 1 ; i <= m ; ++i)
	{
        for(int j = 1 ; j <= t ; ++j)
		{
			f[i][j] = f[i - 1][j] ;
            if(j >= ti[i]) 
				f[i][j] = max(f[i][j], f[i - 1][j - ti[i]] + pri[i]) ;
        }
    }
    cout << f[m][t] ;
	return 0 ;
}

完全背包问题

题目描述

有�​种物品,每种物品的重量为��​,价值为��​。现在需要选出若干件物品放入一个容量为�​的背包中(每种物品可以选任意次),使得在选入背包的物品重量之和不超过容量�​​的前提下,让背包中物品的价值之和最大,求最大价值。

输入描述

第一行两个整数�​、�​(1≤�≤100,1≤�≤103​),分别表示物品数量、背包容量;

第二行为用空格隔开的�​个整数��​(1≤��≤100​),表示物品重量;

第三行为用空格隔开的�​个整数��​(1≤��≤100​),表示物品价值。

输出描述

输出一个整数,表示最大价值。

#include<bits/stdc++.h>
using namespace std;
int a[1002]={0},b[1002]={0};
int f[1002]={0};
int main(){
    int n,v;
    cin>>n>>v;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++){
        for(int j=a[i];j<=v;j++){
			f[j] = max(f[j], f[j - a[i]] +b[i]);
        }
    }
    cout << f[v];
    return 0;
}

01背包问题的方案数

题目描述

有�​件物品,每件物品的重量为��​。现在需要选出若干件物品放入一个容量为�​的背包中(每件物品至多选一次),使得选入背包的物品重量之和恰好等于容量�​​​​。求满足条件的方案数。

输入描述

第一行两个整数�​、�​(1≤�≤100,1≤�≤103​),分别表示物品数量、背包容量;

第二行为用空格隔开的�​个整数��​(1≤��≤10​),表示物品重量。

输出描述

输出一个整数,表示方案数。由于结果可能很大,因此将结果对10007取模后输出。

#include<bits/stdc++.h>
using namespace std;
int main(){
	int N,M;
	cin>>N>>M;
	int a[1005],dp[10050];
	for(int i=1;i<=N;i++){
		cin>>a[i];
	}
	dp[0]=1;
	for(int i=1;i<=N;i++){
		for(int j=M;j>=a[i];j--){
			dp[j]=(dp[j]+dp[j-a[i]])%10007;
		}
	}
	cout<<dp[M];
	return 0;
}

总结

最小消耗能量

题目描述

现有�个从左至右摆放着的高台(编号为从1n),每个高台有各自的高度ℎ�。假设闯关者当前处于第�个高台,那么可以选择跳到第�+1或第�+2个高台(闯关者能够跳任意高度)。如果从第�个高台跳到第�个高台,那么将会消耗闯关者|ℎ�−ℎ�|点能量。问从第1个高台出发、到达第�个高台的过程中需要消耗的最小能量。

输入描述

第一行一个整数�(1≤�≤104),表示高台个数。

第二行为用空格隔开的�个整数ℎ�(1≤ℎ�≤100),表示各高台的高度。

输出描述

一个整数,表示需要消耗的最小能量。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin>>n;
    int a[10002];
    int dp[10002];
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=2;i<=n;i++){
        dp[0]=dp[1]=0;
        dp[i]=dp[i-1]+abs(a[i]-a[i-1]);
        dp[i]=min(dp[i],dp[i-2]+abs(a[i]-a[i-2]));
    }
    cout<<dp[n];
    return 0;

}

矩阵最大权值

题目描述

现有一个�∗�​大小的矩阵,矩阵中的每个元素表示该位置的权值。现需要从矩阵左上角出发到达右下角,每次移动只能向右或者向下移动一格。求最后到达右下角时路径上所有位置的权值之和的最大值。

输入描述

第一行两个整数�​​​​、�​​​​(1≤�≤100,1≤�≤100​​​​),分别表示矩阵的行数和列数;

接下来�​​​行,每行�​​​个整数(−100≤​​整数≤100​​​),表示矩阵每个位置的权值。

输出描述

一个整数,表示权值之和的最大值。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    int a[101][101];
    int dp[101][101]={0};
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            dp[1][1]=a[1][1];
            if(i==1&&j!=1){
                dp[i][j]=dp[i][j-1]+a[i][j];
            }
            if(i!=1&&j==1){
                dp[i][j]=dp[i-1][j]+a[i][j];
            }
            if(i!=1&&j!=1){
                dp[i][j]=a[i][j]+max(dp[i-1][j],dp[i][j-1]);
            }
        }
    }
    cout<<dp[n][m];
    return 0;
}

 最小涂色成本

题目描述

现有�​​​张不同大小的白纸排成一排,每张白纸可以涂成红、黄、蓝三种颜色之一,但不能有连续两张白纸涂成相同的颜色。假设给第�​​​张白纸涂红色需要消耗的成本为��​​​,涂黄色需要消耗的成本为��​​,涂蓝色需要消耗的成本为��​​,求把�​​​​张白纸全部涂色需要的最小成本。

输入描述

第一行一个整数�​​​​​​​​​​​(1≤�≤104​​​​​​​),表示白纸张数;

接下来�行,每行三个整数,表示第�张白纸分别涂红、黄、蓝三种颜色需要消耗的成本��、��、��(1≤��≤100,1≤��≤100,1≤��≤100​)。

输出描述

一个整数,表示最小成本。文章来源地址https://www.toymoban.com/news/detail-857851.html

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin>>n;
    int a[10001][4];
    int dp[10001][4];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=3;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=3;j++){
            if(i==1) dp[i][j]=a[i][j];
            else{
                if(j==1) dp[i][1]=a[i][j]+min(dp[i-1][2],dp[i-1][3]);
                if(j==2) dp[i][2]=a[i][j]+min(dp[i-1][1],dp[i-1][3]);
                if(j==3) dp[i][3]=a[i][j]+min(dp[i-1][1],dp[i-1][2]);
            }  
        }
    }  
    cout<<min(min(dp[n][1], dp[n][2]), dp[n][3]);
    return 0;  

}

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

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

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

相关文章

  • 算法沉淀 —— 动态规划篇(简单多状态dp问题上)

    几乎所有的动态规划问题大致可分为以下5个步骤,后续所有问题分析都将基于此 1.、状态表示:通常状态表示分为以下两种,其中更是第一种为主。 以i为结尾 ,dp[i] 表示什么,通常为代求问题(具体依题目而定) 以i为开始 ,dp[i]表示什么,通常为代求问题(具体依题目而

    2024年04月11日
    浏览(43)
  • 【动态规划专栏】--简单-- 动态规划经典题型

    目录 动态规划 动态规划思维(基础) 状态表示(最重要) 状态转移方程(最难) 初始化(细节) 填表顺序(细节) 返回值(结果) 解码方法⭐⭐ 【题目解析】   【算法原理】 C++ 算法代码 复杂度分析 【空间优化 - 滚动数组】 C++ 算法代码 复杂度分析 【DP边界、初始化

    2024年02月08日
    浏览(79)
  • 力扣:动态规划简单题集解

    一般,只要解决问题的阶段、状态和状态转移决策确定了,就可以写出状态转移方程(包括边界条件)。 根据动态规划的三大基本要素可以设计解题步骤如下: 状态定义: 每个状态的决策,存放每个状态的变量, 状态转移方程: 当前状态与上一个状态之间的关系 初始状态

    2024年02月08日
    浏览(23)
  • 1.20 动态规划(简单)

    目录 动态规划解题思路 动态规划的做题步骤 1. 爬楼梯 2.杨辉三角 3.买卖股票的最佳时机 假设你正在爬楼梯。需要  n  阶你才能到达楼顶。 每次你可以爬  1  或  2  个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 示例 2: 提示: 1 = n = 45  分析:从分析来看,

    2024年01月24日
    浏览(37)
  • 【动态规划】简单多状态

    题目链接 状态表示 dp[i] 表示到i位置的时候预约的最大时长。但是这个题目我们可以选择接或不接。因此可以继续划分为两个子状态: f[i] 表示:到i位置时接受的最大时长 g[i] 表示:到i位置时不接受的最大时长 状态转移方程 初始化 因为这个题目比较简单,所以不需要使用

    2024年02月15日
    浏览(48)
  • 动态规划之简单多状态

    1.题目链接:按摩师 2.题目描述:一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。

    2024年02月09日
    浏览(40)
  • 【算法】动态规划 ⑧ ( 动态规划特点 )

    求解类型 : 动态规划 必须是求 最值 , 可行性 , 方案数 , 三者之一 , 如果求其它内容 , 则不能使用动态规划算法 ; 求最值 : 最大值 , 最小值 等 ; 大规模问题的结果 由 小规模问题 的计算结果 取最大值 大规模问题的结果 由 小规模问题 的计算结果 取最小值 可行性 : 是否可行

    2023年04月08日
    浏览(46)
  • 「动态规划」简单多状态dp问题

    以经典问题“打家劫舍”来解释简单多状态dp问题和解决方法 题目链接:打家劫舍I 这种问题就是在某一个位置有多个状态可以选择,选择 不同的状态 会影响 最终结果 在这道题中就是小偷在每一个房屋,可以选择偷或不偷,每一次选择都会影响最终偷窃金额 状态表示 因为

    2024年03月15日
    浏览(55)
  • c++--简单多状态动态规划问题

    PS:以下代码均为C++实现 1.按摩师  力扣 一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟

    2024年02月14日
    浏览(52)
  • 60题学会动态规划系列:动态规划算法第三讲

    简单多状态问题 文章目录 一.按摩师 二.打家劫舍系列 三.删除并获得点数 四.粉刷房子 力扣链接:力扣 一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,

    2024年02月08日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包