动态规划算法初步总结

动态规划(DP)=状态表示+状态计算

其中:

  状态表示为:集合(前i-1个元素的有限集合构成的最优解)+属性(max or min)

       状态计算为是否将第i个元素加入集合中,即通过判断加入或不加入是否更符合优化目标决定

 

步骤可总结为:

  1. 输入
  2. 为使循环顺利进行,给目标数组赋边界值。多为一维数组为第0位取零,二维数组第0行第0列取零,对角线取零等
  3. 目标数组赋初值, 可赋当前状态-1时的值
  4. 目标数组从1到n循环计算,判断是否将第i个元素加入集合中
  5. 输出数组最后一项

关键在于构造递推方程,正确理解状态概念可以降低构造递推方程的难度

 

目前DP问题代码大都没有成型的步骤和体系,对初学者并不友好,初学者可能陷入仅仅背过一道题的代码而不会处理其它问题的境地。按照以上步骤处理可以解决很多简单的DP问题,实现初步掌握这一类题。

例如:
①0-1背包问题

复制代码
#include <iostream>
using namespace std;
const int N = 1e3+10;
int main()
{
    int n, v; cin >> n >> v;
    int value[N], volume[N];
    int key[N][N];
    for (int i = 1; i <= n; i++)    scanf("%d%d", &volume[i], &value[i]);
    //输入部分

    for (int i = 0; i <= n; i++)
    {
        key[i][0] = 0; key[0][i] = 0;//赋两位下标取0时的边界值

    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= v; j++)
        {
            key[i][j] = key[i - 1][j];//根据当前状态减一给目标数组赋初值
            if (j - volume[i] >= 0)
            {
                int temp = key[i - 1][j - volume[i]] + value[i];
                if (temp > key[i][j])       key[i][j] = temp;
            }//判断是否将第i个元素加入集合中
        }
    }
    cout << key[n][v] << endl;
    return 0;
}
复制代码

 

 

 

 

②图像压缩问题

复制代码
#include <iostream>
#include <cmath>
using namespace std;
const int N = 1e3+10;
int main()
{
    int n; cin >> n;
    int p[N], b[N];
    for (int i = 1; i <= n; i++)    scanf("%d", &p[i]);
    for (int i = 1; i <= n; i++)   b[i] = ceil(log(p[i] + 1) / log(2));
    int key[N]; 
  key[0] = 0;//边界值

for (int i = 1; i <= n; i++)   key[i] = key[i - 1]+ b[i]+11;
//根据当前状态减一给目标数组赋初值
    for (int i = 1; i <= n; i++)
    {
        int bmax=0;
        for (int j =i-2; j >=1; j--)
        {
            if (b[j] > bmax)   bmax = b[j];
            int temp= key[j] + (i - j)*bmax+11;
            if (key[i] > temp)  key[i] = temp;   
        }//判断是否将第i个元素加入集合中
    } 
    cout << key[n];
    return 0;
}
复制代码

 

 

 

 

 

 

 

 

③公共子序列

复制代码
#include <iostream>
using namespace std;
const int N = 1e3+10;
int main()
{
    int n,m; cin >> n>>m;
    char a[N], b[N];
    cin >> a + 1 >> b +1;
    int key[N][N];
    for (int i =0; i <= n; i++)   key[i][0] = 0;
    for (int i = 0; i <=m; i++)   key[0][i] = 0;//边界取零
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            key[i][j] = max(key[i - 1][j],key[i][j-1]);//赋初值
            if (a[i] == b[j])  key[i][j] =max(key[i-1][j-1]+1,key[i][j]);
        }
    }
    cout << key[n][m];
    return 0;
}
复制代码

 

 

 

④矩阵连乘

复制代码
#include <iostream>using namespace std;
const int N = 1e2 + 10;
int main()
{
    int key[N][N],p[N];
    int n; cin >> n;
    for (int i = 0; i <= n; i++)   scanf("%d", &p[i]);
    for (int i = 0; i <= n; i++)     key[i][i] = 0; //边界值
    for (int i = 1; i <= n; i++)
    {
        for (int j = i + 1; j <= n; j++)
        {
            key[i][j] = key[i][j-1]+p[i-1]*p[j-1]*p[j]; //赋间隔为一的初值
            for (int k = i + 1; k <= j; k++)
            {
                int temp = key[i][k]+p[i-1]*p[k]*p[j];
                if (temp < key[i][j])   key[i][j] = temp;
            }
        }
    }
    cout << key[1][n];
    return 0;
}
复制代码

由以上例子可见,对于简单动态规划问题,牢记以上步骤有助于初学者初步入门。进一步提升还需要多多刷题思考总结。

posted @   updateyue  阅读(70)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示