当前位置: 首页 > article >正文

代码随想录算法训练营第三十四天|Day34 动态规划

01背包问题 二维

https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-1.html

视频讲解:https://www.bilibili.com/video/BV1cg411g7Y6

思路

#include <stdio.h>
#include <stdlib.h>
int max(int a, int b) {
    return a > b ? a : b;
}
int main() {
    int n, bagweight;
    scanf("%d %d", &n, &bagweight);
    int *weight = (int *)malloc(n * sizeof(int));
    int *value = (int *)malloc(n * sizeof(int));
    for (int i = 0; i < n; ++i) {
        scanf("%d", &weight[i]);
    }
    for (int j = 0; j < n; ++j) {
        scanf("%d", &value[j]);
    }
    int **dp = (int **)malloc(n * sizeof(int *));
    for (int i = 0; i < n; ++i) {
        dp[i] = (int *)malloc((bagweight + 1) * sizeof(int));
        for (int j = 0; j <= bagweight; ++j) {
            dp[i][j] = 0;
        }
    }
    for (int j = weight[0]; j <= bagweight; j++) {
        dp[0][j] = value[0];
    }
    for (int i = 1; i < n; i++) {
        for (int j = 0; j <= bagweight; j++) {
            if (j < weight[i]) {
                dp[i][j] = dp[i - 1][j];
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
            }
        }
    }
    printf("%d\n", dp[n - 1][bagweight]);

    for (int i = 0; i < n; ++i) {
        free(dp[i]);
    }
    free(dp);
    free(weight);
    free(value);
    return 0;
}

学习反思

首先从输入中读取背包的最大容量和物品个数。然后使用动态内存分配创建weight和value数组来存储每个物品的重量和价值。接下来,创建一个二维数组dp来保存中间结果。dp[i][j]表示在前i个物品中选择,背包容量为j时的最大总价值。接着对dp数组进行初始化,将第一个物品的可选择重量范围内的dp值设置为对应的物品价值。然后,通过一个嵌套循环遍历每个物品和背包容量,计算dp[i][j]的值。如果当前背包容量j小于物品i的重量,说明物品i无法放入背包中,即dp[i][j]等于dp[i-1][j];否则,比较不放入物品i和放入物品i的两种情况下的最大总价值,选取较大值作为dp[i][j]的值。最后,输出dp数组最后一个元素dp[n-1][bagweight]即为问题的解。

01背包问题 一维

https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-2.html

视频讲解:https://www.bilibili.com/video/BV1BU4y177kY

思路

#include <stdio.h>
#include <stdlib.h>
int max(int a, int b) {
    return a > b ? a : b;
}
int main() {
    int n, bagweight;
    scanf("%d %d", &n, &bagweight);
    int *weight = (int *)malloc(n * sizeof(int));
    int *value = (int *)malloc(n * sizeof(int));
    for (int i = 0; i < n; ++i) {
        scanf("%d", &weight[i]);
    }
    for (int j = 0; j < n; ++j) {
        scanf("%d", &value[j]);
    }
    int **dp = (int **)malloc(n * sizeof(int *));
    for (int i = 0; i < n; ++i) {
        dp[i] = (int *)malloc((bagweight + 1) * sizeof(int));
        for (int j = 0; j <= bagweight; ++j) {
            dp[i][j] = 0;
        }
    }
    for (int j = weight[0]; j <= bagweight; j++) {
        dp[0][j] = value[0];
    }
    for (int i = 1; i < n; i++) {
        for (int j = 0; j <= bagweight; j++) {
            if (j < weight[i]) {
                dp[i][j] = dp[i - 1][j];
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
            }
        }
    }
    printf("%d\n", dp[n - 1][bagweight]);

    for (int i = 0; i < n; ++i) {
        free(dp[i]);
    }
    free(dp);
    free(weight);
    free(value);
    return 0;
}

学习反思

首先从输入中读取背包的最大容量和物品个数。然后使用动态内存分配创建weight和value数组来存储每个物品的重量和价值。接下来,创建一个二维数组dp来保存中间结果。dp[i][j]表示在前i个物品中选择,背包容量为j时的最大总价值。接着对dp数组进行初始化,将第一个物品的可选择重量范围内的dp值设置为对应的物品价值。然后,通过一个嵌套循环遍历每个物品和背包容量,计算dp[i][j]的值。如果当前背包容量j小于物品i的重量,说明物品i无法放入背包中,即dp[i][j]等于dp[i-1][j];否则,比较不放入物品i和放入物品i的两种情况下的最大总价值,选取较大值作为dp[i][j]的值。最后,输出dp数组最后一个元素dp[n-1][bagweight]即为问题的解。

416. 分割等和子集

思路

bool canPartition(int* nums, int numsSize) {
    int total = 0;
    for (int i = 0; i < numsSize; i++) {
        total += nums[i];
    }
    if (total % 2 != 0) {
        return false;
    }
    int target = total / 2;
    bool dp[target + 1];
    for (int i = 0; i <= target; i++) {
        dp[i] = false;
    }
    dp[0] = true; 
    for (int i = 0; i < numsSize; i++) {
        for (int j = target; j >= nums[i]; j--) {
            dp[j] = dp[j] || dp[j - nums[i]];
        }
    }
    return dp[target]; 
}

学习反思

首先计算数组中所有元素的总和,如果总和为奇数,则无法分割成两个和相等的子集,直接返回false。然后,计算目标值target,即总和的一半。创建一个bool类型数组dp,大小为target+1,用来保存是否能够组成和为对应索引的子集。dp[i]为true表示能够组成和为i的子集,dp[i]为false表示不能组成和为i的子集。初始化dp数组,将所有元素初始化为false,然后将dp[0]设置为true,表示和为0的子集一定可以组成。接下来,使用两个嵌套循环遍历数组和目标值。对于每个元素nums[i],从目标值target开始向前遍历,如果能够组成和为j - nums[i]的子集,即dp[j - nums[i]]为true,那么当前位置的dp[j]也设置为true。循环结束后,如果dp[target]为true,则表示数组可以分割为两个和相等的子集,返回true;否则返回false。

总结

动态规划,加油!!!


http://www.kler.cn/a/378280.html

相关文章:

  • Docker部署Meta-Llama-3.1-70B-Instruct API openai格式,vLLM速度对比
  • 钉钉向广告低头
  • 基于Openwrt系统架构,实现应用与驱动的实例。
  • OpenAI 提示工程指南详解
  • 深入学习 Scrapy 框架:从入门到精通的全面指南
  • STM32MP135 linux6.1.82版本移植RTL8723DS WIFI驱动
  • 四川无人机航测服务公司产品应用案例
  • 深度学习揭秘:神经网络如何模拟人脑
  • 100种算法【Python版】第38篇——Boyer-Moore算法
  • Python 如何在 Web 环境中使用 Matplotlib 进行数据可视化
  • PyQt入门指南四十 图形视图框架Graphics View
  • 使用WebStorm开发Vue3项目
  • 18.04Ubuntu遇到Unable to locate package
  • Games101笔记-三维Transform变换(三)
  • 手机怎么玩森林之子?远程玩森林之子教程
  • 【解决】Linux环境中mysqlclient安装失败问题
  • LLM懂不懂揣摩式思考
  • 华为大数据和数据库有关系吗?
  • 面试问题:hash和history的区别
  • 正式开源:从 Greenplum 到 Cloudberry 迁移工具 cbcopy 发布
  • Chrome浏览器音/视频无法自动播放
  • 微服务设计模式 - 网关路由模式(Gateway Routing Pattern)
  • dns主从服务器的配置
  • Web 词汇表
  • Linux下安装ActiveMQ-CPP
  • 基于Spring Boot的私房菜定制上门服务系统的设计与实现