临近蓝桥杯比赛了,今天学习了两道动态规划的题目进行笔记的整理,同时将代码和题目的要求分享给大家,也是作为自己练习完的笔记整理。
动态规划
概念
动态规划(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;
}
希望上面的讲解能给大家提供到帮助。