继续第二波蓝桥之旅,昨天听大神讲了动态规划。于是回来把代码都敲了一下,基本理解了三要素:1.初始化 。2.状态转移方程:这个是动态规划的灵魂,不过我目前并没有掌握精髓。
状态转移方程就是通过前面一步来求出这一步的优质解。最后返回最优解。
能采用动态规划求解的问题的一般要具有3个性质:
(1) 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
(2) 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
(3)重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)
下面贴出来几个动规的题
1.求一个金字塔形数组的最大路径和
#include <stdio.h>
#define N (3)
#define MAX(a,b) (a > b ? a : b)
int a[N][N] = {{2,0,0},{4,3,0},{4,10,3}};
int get_max(void);
//金字塔型的数组,求路径上的最大值。
// 2
// / \
// 4 3
// / \ / \
// 4 9 5
// 2
// 4 3
// 4 9 5
//行从后向前遍历,列从前向后遍历。
int get_max(void)
{
int dp[N][N] = {0};
int i = 0;
int j = 0;
//初始化,让最后一行等于a的最后一行
i = N - 1;
for(j = 0; j < N; ++j){
dp[i][j] = a[i][j];
}
//状态转移方程。dp[i][j]等于dp[i+1][j+1]和dp[i+1][j]的大者+a[i][j]
//直到到顶端
for(i = N-2; i >= 0; --i){
for(j = 0; j <= i; ++j){
<strong>dp[i][j] = MAX(dp[i+1][j+1],dp[i+1][j]) + a[i][j];</strong>
}
}
//返回max
return dp[0][0];
}
int main(int argc,char *argv[])
{
int max = 0;
max = get_max();
printf("%d\n",max);
return 0;
}
2.lcs问题,求最大公共子序列
#include <stdio.h>
#include <string.h>
#define MAX(a,b) (a > b ? a : b)
int get_max(const char *str1,const char *str2,int m,int n);
//最长子序列的长度,m是str1的长度,n是str2的长度
int get_max(const char *str1,const char *str2,int m,int n)
{
int i = 0;
int j = 0;
int flag;
int dp[6][5] = {0};
int temp = 0;
//初始化
//状态转移方程,dp[i][j]等于
//dp[i-1][j-1]+flag(flag表示是否匹配),dp[i-1][j],dp[i][j-1]三者的最大值
for(i = 0; i < m; ++i){
for(j = 0; j < n; ++j){
flag = 0;
if(str1[i] == str2[j]){
flag = 1;
}
<strong>temp = MAX(dp[i][j+1], dp[i][j] + flag);
dp[i+1][j+1] = MAX(temp,dp[i][j+1]);</strong>
}
}
//返回最大值
return dp[i][j];
}
int main(int argc,char *argv[])
{
char *str1 = "happy";
char *str2 = "papy";
int max = 0;
max = get_max(str1,str2,strlen(str1),strlen(str2));
printf("%d\n",max);
return 0;
}
3.01背包问题
#include <stdio.h>
#define N (4)
#define CONTAIN (6)
#define MAX(a,b) a > b ? a : b
int a[2][N] = {{1,2,3,4},
{2,2,3,9}};
//01背包:有n个包,价值各不相同,而且每个包都不能再拆分成小的包
//给定一个容器的最大容量,求得这个容器的最大价值
//a[0]存放质量,a[1]存放价值
//下标 0 1 2 3
//重量 1 2 3 4
//价值 2 2 3 9
///
//二维表
// 0 1 2 3 4 5 6 容量
//
//0 0 2 2 3 9 9 11 价值
//1 0 0 2 3 9 9 11
//2 0 0 0 3 9 9 9
//3 0 0 0 0 9 9 9
//4 0 0 0 0 0 0 0
//箱子下标
int get_max(void);
int get_max(void)
{
int i = 0;
int j = 0;
int dp[N+1][CONTAIN+1] = {0};
//初始化
//状态转移方程
for(i = N-1; i >= 0; --i){
for(j = 0; j <= CONTAIN; ++j){
//如果容量小于当前箱子的大小,那么就让这个值等于它的上一步的值
if(j < a[0][i]){
dp[i][j] = dp[i+1][j];
}
//如果容量大于当前箱子,那么就找到上一步未放置该箱子时的值
//加上当前箱子的价值,与它的上一步值相比较,得出最大值赋给它
else{<strong>
dp[i][j] = MAX(dp[i+1][j],dp[i+1][j-(a[0][i])] + a[1][i]);</strong>
}
}
}
return dp[0][CONTAIN];
}
int main(int argc,char *argv[])
{
int max = 0;
max = get_max();
printf("%d\n",max);
return 0;
}