动态规划经典案例学习笔记

一)斐波纳契

#include<bits/stdc++.h>
using namespace std;
int n;
int dp[1000];
int dpFun(int n){
    if(dp[n])
        return dp[n];
    if(n==1||n==2)
        return 1;
    int ans=dpFun(n-1)+dpFun(n-2);
    dp[n]=ans;
    return ans;
}
int main()
{
    cin >> n ;
    cout << dpFun(n)<< endl;
    return 0;
}

二)数塔问题

1、记忆化搜索

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int inf = 1e9;
int dp[maxn][maxn] , a[maxn][maxn];
int n , m;
// dfs的作用:求从x,y到底部的路径最大值
int dfs (int x , int y)
{
    // 边界条件
    // 不合法的状态,我们要让他一定不被考虑。
    // 如果全部都是负数,那么返回0将是错误的结果
    if (y > x) return -inf;
    if (dp[x][y] != -1) return dp[x][y];
    if (x == n + 1) return 0;
    int ans = a[x][y] + max (dfs(x + 1 , y) , dfs(x + 1 , y + 1));
    dp[x][y] = ans;
    return ans;
}
int main()
{
    // 把所有dp置为-1
    // memset 不是什么值都可以赋的!
    // 只能初始化0 || -1
    memset(dp , -1 , sizeof dp);
    cin >> n >> m;
    for (int i = 1 ; i <= n; i ++){
        for (int j = 1 ; j <= i ; j++){
            cin >> a[i][j];
        }
    }
    cout << dfs(1 , 1) << endl;
    return 0;
}

2、递推

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int inf = 1e9;
// dp(x , y) 从(x , y)到最下面一层的最大值
int dp[maxn][maxn] , a[maxn][maxn];
int main()
{
    int t; cin >> t;
    while (t--){
        // 初始化
        memset (dp , 0 , sizeof dp);
        int n; 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 = 1 ; j <= i ; j++){
                dp[i][j] = a[i][j] + max(dp[i + 1][j] , dp[i + 1][j + 1]);
            }
        }
        cout << dp[1][1] << endl;
    }
    return 0;
}

三)最大子段和

PS:求L到R最大的和


int a[100],b[100],c[100];
//a存数据,b[i]存以i结尾的最大子段和
b[i]=max(a[i]+b[i-1],a[i]);
//c存以i结尾的最大子段和的起始点
/*c[i]=c[i]+1;
c[i]=i;
*/

四)序列组合

1、所有相邻的数a[i]-a[i-1]的绝对值<=2
DFS方法

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int inf = 1e9;
int n , m;
// dfs (st , val) 求从st填写到1格子的所有可能方案.
int dp[105][108];
int dfs (int st , int val)
{
    if (dp[st][val] != -1) return dp[st][val];
    if (st == 0) return 1;
    int ans = 0;
    for (int i = 1 ; i <= m ; i++){
        if (abs(val - i) <= 2){
            ans += dfs(st - 1 , i);
        }
    }
    dp[st][val] = ans;
    return ans;
}
int main()
{
    memset(dp , -1 , sizeof dp);
    cin >> n >> m;
    int ans = 0;
    for (int i = 1 ; i <= m ; i++){
        ans += dfs (n - 1 , i);
    }
    cout << ans << endl;
    return 0;
}

递推方法

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int inf = 1e9;
int n , m;
// dp(i , j) 代表从1号格子填写到第i号格子,且第i号格子的数为j的所有方案数.
int dp[maxn][maxn];
int main()
{
    memset(dp , -1 , sizeof dp);
    int n , m; cin >> n >> m;
    // 边界条件,因为1之前没有格子了
    for (int i = 1 ; i <= m ; i++)
        dp[1][i] = 1;
    // 从2开始转移.
    for (int i = 2 ; i <= n ; i++){
        for (int j = 1 ; j <= m ; j++){
            for (int k = max(j - 2 , 1) ; k <= min(j + 2 , m) ; k++){
                dp[i][j] += dp[i - 1][k];
            }
        }
    }
    int ans = 0;
    for (int i = 1 ; i <= m ; i++){
        ans += dp[n][i];
    }
    cout << ans << endl;
    return 0;
}

五)LIS:最长上升子序列


dp[i]=max(dp[j]+1);   j属于[1,i-1];  dp[j]<dp[i]
O(n^2);

六)走格子

PS:从第一个点走到第二个点(只能向下走和向右走)

//dp[i][j]=dp[i][j+1]+dp[i+1][j];
#include <bits/stdc++.h>

using namespace std;
int bk[1000][1000];
int main(){
    int n,m,Q;
    cin>>n>>m;
    for(int i=2;i<=m;i++)
        bk[1][i]=bk[1][i-1]+1;
       //先将最顶上的格子向右走完
    for(int i=2;i<=n;i++)
        for(int j=1;j<=m;j++)
           bk[i][j]=bk[i-1][j]+1;
        //再将向下走的格子走完
    cin>>Q;
    while(Q--){
    	//Q次询问<1,1>走到<x,y>需要多少步
        int x,y;
        cin>>x>>y;
        cout<<bk[x][y]<<endl;
    }
    return 0;
}

七)LCS:最长公共子序列

PS:求两个字符串最长公共子串


第一个字符串的前i个字符与第二个字符串j个字符最长公共子序列的长度
if(x==y){
	dp(i,j)=dp(i-1,j-1)+1;
}else{
	dp(i,j)=max(dp(i-1,j),dp(i,j-1));
}

八)回文串模型

1、一个字符串长度为2000,Q次询问[L,R]子串是否为回文子串


dp(L,R)=dp(L+1,R-1)&&s[L]==s[R];

2、最长回文子序列
PS:字符串的第i个字符到第j个字符最长回文子串序列的长度


if(x==y){
	dp(i,j)=dp(i+1,j-1)+1;
}else{
	dp(i,j)=max(dp(i+1,j),dp(i,j-1));
}

背包模型

PS:一个体积V的背包,N个物品(x,y)x表示物品体积,y表示物品价值,不超过背包容器求价值最大化(V,x<=100),y<1e9


ST第几个物品 V体积和 W价值和
DFS(int ST,int V,int W);

dfs(int st,int v){
	max(dfs(st+1,v),W[st]+dfs(st+1,v-V[st]));
	W[st]表示st的价值,
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ja Vas Kokhaju

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值