动态规划学习 ——例题:乘积最大,传球游戏

本文介绍了动态规划的基本概念,包括其在解决多阶段决策问题中的应用,以及通过两个实例——传球游戏和背包问题——详细解释了如何将问题分解为子问题并利用动态规划求解。文中还涉及字符转换和矩阵表示在动态规划中的重要性。
摘要由CSDN通过智能技术生成

临近蓝桥杯比赛了,今天学习了两道动态规划的题目进行笔记的整理,同时将代码和题目的要求分享给大家,也是作为自己练习完的笔记整理。

动态规划

概念

      动态规划(Dynamic Programming,简称DP)是运筹学的一个分支,它用于求解多阶段决策过程的最优化问题。这种方法通过将原问题分解为相对简单的子问题,并利用子问题的答案来减少重复计算,从而求解复杂问题。此外,动态规划还可以处理决策变量时间上的变化和决策过程的相互关系。动态规划的思想和方法在《算法导论》和《运筹学》等书籍中有详细的介绍,并且它在计算机科学与技术领域中是一种常见的算法思想。

多决策问题

       在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。因此各个阶段决策的选取不能任意确定,它依赖于当前面临的状态,又影响以后的发展。当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线。这种把一个问题看作是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题称为多阶段决策问题。

例题

传球游戏

这道题其实很重要的一个问题,也是比较难的一点是将输入的实例转化成数字,根据输入的样例就是需要我们将char类型的字符串转换成为int类型,这个地方是比较难的一点,如果能做好这个下面的其实也就比较常规的符合dp题目的套路。


代码如下 并且附有讲解:

#include<stdio.h>
#define max(a,b) a>b?a:b
long long dp[42][8];//dp[i][j]表示i个数j个乘号的最大值,设想成矩阵表示 
char c[42]; 
long long num(int a,int b){//将第a位到第b位的字符转为数字 
    int i,sum=0;
    for(i=a;i<=b;i++)
        sum=sum*10+c[i-1]-'0';
    return sum;
}
int main(){
    int n,k,i,j,x;
    scanf("%d%d",&n,&k);
    scanf("%s",c);
    for(i=1;i<=n;i++)
        dp[i][0]=num(1,i);//填补矩阵中没有乘号有用的dp值
    for(i=2;i<=n;i++){
        for(j=1;j<=k&&j<i;j++)//i个数最多能加入i-1个乘号 
        for(x=1;x<i;x++)//x表示将乘号插入的位置 ,x不能大于i
            dp[i][j]=max(dp[i][j],dp[x][j-1]*num(x+1,i)); //一直取最大值 
    }
    printf("%d",dp[n][k]);
    return 0;
}

传球游戏

传球游戏是比较简单的动态规划,只需要考虑到两端的特殊情况,因为我们使用的是数组而不是双向链表,所以需要考虑到最后一位同学和第一位同学的传球情况,所以需要特地的举例出来但是这题是比较简单的动态规划问题。


#include <iostream>
using namespace std;
int n, m;
int dp[35][35];//dp[n][m]物品1~n,背包体积m次,表示物品i在j次传回自己的方式多少种 
int main()
{
    cin >> n >> m;
    dp[1][0]=1;
    for (int j = 1; j <= m; j++)//有序,所以先遍历背包 
    {
        for (int i = 1; i <= n; i++)
        {
            if (i == 1)
                dp[i][j] = dp[n][j - 1] + dp[i + 1][j - 1];//首时特殊情况 ,传右传尾 
            else if (i == n)
                dp[i][j] = dp[i - 1][j - 1] + dp[1][j - 1];//尾时特殊情况 ,传左传首 
            else
                dp[i][j] = dp[i - 1][j - 1] + dp[i + 1][j - 1];//递推公式,传左还是传右 
        }
    }
    cout << dp[1][m];
    return 0;
}

希望上面的讲解能给大家提供到帮助。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值