算法设计与分析 | 动态规划

算法简介

动态规划(Dynamic Programming,简称DP)是一种通过把原问题分解为相互重叠的子问题,并仅仅解决每个子问题一次,将其解保存在一个表格中,从而避免重复计算,提高效率的算法思想。

动态规划的基本思想可以概括为以下几个步骤:

  1. 划分子问题: 将原问题划分为若干个规模较小的子问题。

  2. 解决子问题: 递归地或迭代地求解子问题。通常,通过保存子问题的解避免重复计算。

  3. 合并子问题的解: 将子问题的解组合起来,得到原问题的解。

同时,在使用动态规划时,需注意问题的以下两个性质

  1. 重叠子问题(Overlapping Subproblems): 原问题可以分解为若干个相同的子问题。解决这些子问题只需要一次计算,并将结果存储以避免重复计算。

  2. 最优子结构(Optimal Substructure): 问题的最优解可以通过子问题的最优解推导出。

例题两道

1. 0-1背包问题

问题描述:有 N 件物品和一个容量是 V的背包。每件物品只能使用一次。第 i 件物品的体积是 v_i,价值是 w_i。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。

题解:

初始化f数组的第i行第j列为背包容量为j的情况下在前i件物品中可装入的最大价值,对背包容量(列)进行遍历,对物品(行)进行动态规划,具体如下:

  • 若j大于当前物品容量,则选择是否加入此物品;
  • 否则,不能加入此物品;

时间复杂度为O(n×v),c++代码如下:

cpp 复制代码
#include <iostream>
#include <algorithm>

using namespace std;

int main(){
    int n, v;
    cin >> n >> v;
    int volume[n], money[n];
    int f[n+1][v+1] = {0};
    for(int i = 1; i <= n; i++)
        cin >> volume[i] >> money[i];
    int value = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 0; j <= v; j++) {
            if(j >= volume[i]) 
                f[i][j] = max(f[i-1][j], f[i-1][j-volume[i]] + money[i]);
            else
                f[i][j] = f[i-1][j];
        }
    cout << f[n][v] << endl;
    return 0;
}

2. 最大子矩形问题

问题描述:给定一个包含整数的二维矩阵,子矩形是位于整个阵列内的任何大小为 1×1或更大的连续子阵列。矩形的总和是该矩形中所有元素的总和。在这个问题中,具有最大和的子矩形被称为最大子矩形。

题解:

初始化sum数组的第i行第j列为二维矩阵第i行第0位到第j位的和sum[i][j] = sum[i][j-1] + matrix[i][j],对列进行遍历,对行进行动态规划,具体如下:

  • k、j为列标,表示遍历(k,j)列的内容;
  • i为行标,表示是否加上第i行第(k,j)列的和;

最后取最大值即可,时间复杂度为O( n^ 3),c++代码如下:

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;
int main(){
    int n;
    cin >> n;
    int matrix[n+1][n+1], sum[n+1][n+1] = {0};
    for(int i = 1; i < n+1; i++)
        for(int j = 1; j < n+1; j++){
            cin >> matrix[i][j];
            sum[i][j] = sum[i][j-1] + matrix[i][j];
        }
    int ans = -1000;
    for(int j = 1; j <= n ; j++)
        for(int k = 0; k < j; k++){
            int temp = 0;
            for(int i = 1; i <= n; i++){
                temp = max(sum[i][j] - sum[i][k], temp + sum[i][j] - sum[i][k]);
                ans = max(ans,temp);
            }
        }
    cout<<ans<<endl;
    return 0;     
}
相关推荐
AI视觉网奇17 小时前
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr
开发语言·c++·算法
ghie909017 小时前
ECG波形检查与分析系统
算法
智者知已应修善业17 小时前
【输入两个数字,判断两数相乘是否等于各自逆序数相乘】2023-10-24
c语言·c++·经验分享·笔记·算法·1024程序员节
Shingmc318 小时前
【Linux】进程控制
linux·服务器·算法
阿正的梦工坊18 小时前
DreamGym:通过经验合成实现代理学习的可扩展化
人工智能·算法·大模型·llm
小武~18 小时前
Leetcode 每日一题C 语言版 -- 45 jump game ii
c语言·算法·leetcode
行云流水62619 小时前
前端树形结构实现勾选,半勾选,取消勾选。
前端·算法
laocooon52385788619 小时前
一个C项目实现框架
c语言·算法
c#上位机20 小时前
halcon图像增强——图像取反
图像处理·算法·c#·halcon
zheyutao20 小时前
割点和桥
算法·图论