C语言动态规划多种背包问题分析讲解

C语言动态规划多种背包问题分析讲解

背包问题介绍

背包问题是动态规划中比较常见的问题之一,特别是在算法竞赛中。

一般来说,背包问题可分为两大类:01背包和完全背包。01背包是每个物品只能用一次,而完全背包则是每个物品可以无限制使用。

这里将介绍多种背包问题的分析和具体实现。

01背包问题

问题描述

有一个容量为V的背包和N个物品,每个物品的体积为v[i],价值为w[i],求在装满背包的前提下,最大化能够获得的总价值。

分析与实现

01背包问题采用二维数组dp[i][j]记录放置前i个物品,总体积不超过j时的最大价值。

具体地,依次枚举物品i和容量j(即i和j的范围分别为[1, N] 和[1, V] ),讨论第i个物品是否放入背包中:

  1. 若第i个物品的体积大于j,则不放入,此时dp[i][j]的值应该和dp[i-1][j]相同;
  2. 若第i个物品的体积小于等于j,则可以将其放入背包中,此时dp[i][j]应该等于dp[i-1][j-v[i]] + w[i];
  3. 比较第1步和第2步中两种情况所对应的dp值,选择其中较大的值即可。

下面是C语言的实现代码:

#include <stdio.h>
#include <string.h>

#define maxn 1005

int max(int a, int b) {
    return a > b ? a : b;
}

int main() {
    int N, V;
    int v[maxn], w[maxn];
    int dp[maxn][maxn];

    scanf("%d%d", &N, &V);

    for (int i = 1; i <= N; i++)
        scanf("%d%d", &v[i], &w[i]);

    memset(dp, 0, sizeof(dp));

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= V; j++) {
            if (j < v[i])
                dp[i][j] = dp[i - 1][j];
            else
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
        }
    }

    printf("%d\n", dp[N][V]);

    return 0;
}

完全背包问题

问题描述

有一个容量为V的背包和N个物品,每个物品的体积为v[i],价值为w[i],每种物品都有无限个。在装满背包的前提下,最大化能够获得的总价值。

分析与实现

完全背包问题的dp数组和01背包问题一样是二维数组,但转移方程有所不同。

对于每个物品i,依次枚举背包中放入第i个物品的数目(即可能的xi,范围为[0, V/v[i]]),讨论第i个物品所能带来的价值:

  1. 若不放入第i个物品,则dp[i][j]的值应直接等于dp[i-1][j]。
  2. 若放入x个第i个物品,则dp[i][j]等于dp[i][j-xv[i]] + xw[i](这里借用前面提到的完全背包思想,将此方程写成这样)。

由此可得dp转移方程为:

dp[i][j] = max(dp[i-1][j], dp[i][j-v[i]] + w[i])

下面是C语言的实现代码:

#include <stdio.h>
#include <string.h>

#define maxn 1005

int max(int a, int b) {
    return a > b ? a : b;
}

int main() {
    int N, V;
    int v[maxn], w[maxn];
    int dp[maxn][maxn];

    scanf("%d%d", &N, &V);

    for (int i = 1; i <= N; i++)
        scanf("%d%d", &v[i], &w[i]);

    memset(dp, 0, sizeof(dp));

    for (int i = 1; i <= N; i++) {
        for (int j = v[i]; j <= V; j++) {
            dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i]);
        }
    }

    printf("%d\n", dp[N][V]);

    return 0;
}

示例说明

下面使用两个示例来说明上面介绍的两个问题。

示例1

输入:
4 5
1 2
2 4
3 4
4 5
输出:
9

解释:

这里有4个物品,容量为5,物品分别为1:(1,2),2:(2,4),3:(3,4),4:(4,5)。

使用01背包算法,可以得到最大价值为9,选择物品1和2。

示例2

输入:
4 5
1 2
2 4
3 4
4 5
输出:
10

解释:

这里与示例1相同,但与示例1不同的是,这里使用完全背包算法,最大价值为10,其中选择了物品2和4。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言动态规划多种背包问题分析讲解 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • 详解C++中shared_ptr的使用教程

    详解C++中shared_ptr的使用教程 什么是shared_ptr shared_ptr是C++11语言引入的一种智能指针,用于管理动态分配的内存,避免因手动释放内存而引发的内存泄漏等问题。 shared_ptr采用引用计数机制来跟踪内存资源的使用情况,并当引用计数为0时自动释放内存。这使得shared_ptr不仅可以确保资源的正确释放,而且还能够方便地…

    C 2023年5月22日
    00
  • C语言圣诞树的实现示例

    C语言圣诞树的实现示例 在这个示例中,我们将会使用C语言来实现一个圣诞树的输出效果。代码中将会用到循环、条件语句、字符输出、延时等知识点,让我们一起来看看该如何实现吧。 实现思路 实现圣诞树的思路很简单,我们可以分成两个部分来实现: 打印出圣诞树的形状,包括树干和树叶部分。 在圣诞树上挂上圣诞灯,增添节日气氛。 代码实现 基本思路讲解完了,我们来看看代码: …

    C 2023年5月23日
    00
  • C++找出字符串中出现最多的字符和次数,时间复杂度小于O(n^2)

    题目描述 给定一个包含n个字符的字符串S,请你编写一个复杂度小于O(n^2)的算法,找出字符串S中出现最多的字符和次数。 思路分析 本题可以采用哈希表来实现。具体的做法是,在扫描整个字符串的过程中记录下每个字符出现的次数,然后遍历所有字符,找出出现次数最多的字符即可。 遍历字符串的时间复杂度为O(n),统计每个字符出现次数的过程为O(n),遍历哈希表找到出现…

    C 2023年5月22日
    00
  • C语言用指针支持树

    关于“C语言用指针支持树”的完整使用攻略,我准备分为以下几个部分进行讲解: 树的定义与基本操作 使用指针实现树节点 树的遍历算法 示例程序 树的定义与基本操作 树是一种非常常见的数据结构,其结构非常清晰,由若干个节点组成,每个节点之间有唯一的父子关系。 一些常见的树操作包括: 插入节点:在树中插入一个新节点,将其作为指定节点的子节点。 删除节点:从树中删除给…

    C 2023年5月9日
    00
  • C++ 中类对象类型的转化的实例详解

    C++ 中类对象类型的转化的实例详解 什么是类型转换? 类型转换是将数据从一种数据类型转换为另一种数据类型的过程。在 C++ 中,有几种类型转换的方式: 隐式类型转换:在表达式中,某些情况下,C++ 会自动将一种类型转换为另一种类型。例如,int x = 10; float y = x; 在将 int 类型赋值给 float 类型时,C++ 会自动完成数据类…

    C 2023年5月22日
    00
  • 详解几十行代码实现一个vue的状态管理

    下面我将详细讲解如何实现一个vue的状态管理。 1. 状态管理器的作用 在使用Vue进行大型前端应用开发时,随着组件数量的增加,组件之间的状态共享也变得越来越复杂。这时候就需要一个或多个状态管理器来维护应用的整体状态,使得组件间的状态共享变得更加灵活、稳定。 2. 状态管理器的实现 一个简单的vue状态管理器有以下几个基本要素: 2.1. 状态(state)…

    C 2023年5月23日
    00
  • C 共用体

    C语言共用体(Union)完整使用攻略 共用体(Union)是C语言中一种特殊的数据类型,与结构体(Struct)类似,也是一种复合类型。共用体允许不同的数据类型在相同的内存空间里互相转换使用,这意味着在同一时间只能保存相同的数据类型,但可以在不同的时间存储不同的数据类型。 创建共用体 共用体和结构体的方式非常相似,可以使用关键字union来定义共用体,例如…

    C 2023年5月10日
    00
  • LUNC币怎么购买交易?LUNC币买卖交易操作教程

    LUNC币是一种基于以太坊的ERC-20代币,主要用于中立联盟链平台上的交易和支付,下面是一份 LUNC币购买交易的操作教程。 步骤一:创建数字钱包 在进行LUNC币的购买交易前,您需要先创建一份数字钱包并备份好钱包的助记词。目前流行的数字钱包有MetaMask、MyEtherWallet和imToken等。一般来说,数字钱包会生成一个地址,然后你需要将以太…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部