动态规划问题,大致可以分为两类:
一是最优解问题,其目的是求某个问题的最小值或最大值。
如:10000以内的k好数中任选三个的和,最大值为多少。
二是组合问题,其目的是求某个事情发生的概率。
如:长度为x的数字字符串,可以分解为4个小于255的数字,可以有多少种组合方式。
面对这两种问题的解决方案也有两种:
自上而下(记忆存储):从顶端开始分解问题,分解到最小并解决,然后返回保存的答案。如斐波拉契数列问题的递归求法便是记忆存储法。
自下而上(表格填充):先解决较小的子问题,由子问题的解推算出后续问题的解,从而得到最佳解法。如斐波拉契数列问题的递归求法便是表格填充法。
至于什么情况下使用什么方法,还需要具体情况具体分析。
如
数学三角形问题(动态规划);
在输入的数学三角形中寻找一条从顶部到底部的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或右下行进。只需给出最大和,不需给出具体路径。
1<三角形行数<100,0<数字<99
输入格式:
5//行数
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出格式:
30
自顶向下的解法:
#include <iostream>
#include <vector>
using namespace std;
void math_triangle_top()
{
//接收输入,使用2维vector存储
int n;
cin>>n;
vector<vector<int>> my_vector(n);
for (int i=0;i<my_vector.size();i++)
{
my_vector[i].resize(n);
}
//正着存的
int k=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(j<k)
{
cin>>my_vector[i][j];
}
else
{
my_vector[i][j]=0;
}
}
k+=1;
}
//开始一层,一层的计算,更新状态数组
for (int i=1;i<my_vector.size();i++)
{
for(int j=0;j<my_vector[0].size();j++)
{
if(my_vector[i][j]!=0)
{
if(j==0)
{
my_vector[i][j]+=my_vector[i-1][j];
}
else
{
if(my_vector[i-1][j]>my_vector[i-1][j-1])
{
my_vector[i][j]+=my_vector[i-1][j];
}
else
{
my_vector[i][j]+=my_vector[i-1][j-1];
}
}
}
}
}
cout<<"状态数组值为:"<<endl;
//输出状态数组中的内容
for (int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cout<<my_vector[i][j]<<" ";
cout<<endl;
}
//比较得出最大值
int num_max=0;
for (int i=0;i<n;i++)
{
if(num_max<my_vector[n-1][i])
{
num_max=my_vector[n-1][i];
}
}
cout<<"最大值为:"<<endl;
cout<<num_max;
}
自下而上的解法:
#include <iostream>
#include <vector>
using namespace std;
void math_triangle_end()
{
//接收输入,使用2维vector存储
int n;
cin>>n;
vector<vector<int>> my_vector(n);
for (int i=0;i<my_vector.size();i++)
{
my_vector[i].resize(n);
}
//倒着存的
int k=1;
for(int i=my_vector.size()-1;i>=0;i--)
{
for(int j=0;j<my_vector[0].size();j++)
{
if(j<k)
{
cin>>my_vector[i][j];
}
else
{
my_vector[i][j]=0;
}
}
k+=1;
}
//开始自下而上的计算,更新状态数组
for (int i=1;i<my_vector.size();i++)
{
for(int j=0;j<my_vector[0].size();j++)
{
if(my_vector[i][j]!=0)
{
if(my_vector[i-1][j]>my_vector[i-1][j+1])
{
my_vector[i][j]+=my_vector[i-1][j];
}
else
{
my_vector[i][j]+=my_vector[i-1][j+1];
}
}
}
}
//输出所有值
cout<<"状态数组值为:"<<endl;
for (int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cout<<my_vector[i][j]<<" ";
cout<<endl;
}
//输出最后一个值即可
cout<<"最大值为:"<<endl;
cout<<my_vector[n-1][0];
}
总结:动态规划,其实就是弄一个状态矩阵,记录计算过程中每一步的计算结果,并将每次的计算结果进行一个累加,由此得到最终的答案。